Merge "Remove unnecessary input event indirection"
diff --git a/Android.mk b/Android.mk
index bcab276..b9035ff 100644
--- a/Android.mk
+++ b/Android.mk
@@ -255,10 +255,14 @@
 	media/java/android/media/IAudioService.aidl \
 	media/java/android/media/IAudioFocusDispatcher.aidl \
 	media/java/android/media/IAudioRoutesObserver.aidl \
+	media/java/android/media/IMediaRouterClient.aidl \
+	media/java/android/media/IMediaRouterService.aidl \
 	media/java/android/media/IMediaScannerListener.aidl \
 	media/java/android/media/IMediaScannerService.aidl \
 	media/java/android/media/IRemoteControlClient.aidl \
 	media/java/android/media/IRemoteControlDisplay.aidl \
+	media/java/android/media/IRemoteDisplayCallback.aidl \
+	media/java/android/media/IRemoteDisplayProvider.aidl \
 	media/java/android/media/IRemoteVolumeObserver.aidl \
 	media/java/android/media/IRingtonePlayer.aidl \
 	telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl \
@@ -622,9 +626,9 @@
 		-samplecode $(sample_dir)/BasicSyncAdapter \
  		            samples/BasicSyncAdapter "" \
 		-samplecode $(sample_dir)/StorageClient \
- 		            samples/StorageClient "" 
-#		-samplecode $(sample_dir)/StorageProvider \
-# 		            samples/StorageProvider "" 
+ 		            samples/StorageClient "" \
+		-samplecode $(sample_dir)/StorageProvider \
+ 		            samples/StorageProvider ""
 #       -samplecode $(sample_dir)/AndroidBeamDemo \
 # 		            samples/AndroidBeamDemo "Android Beam Demo" \
 # 		-samplecode $(sample_dir)/ApiDemos \
diff --git a/api/current.txt b/api/current.txt
index 8ec81b7..7e757b5 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -29666,6 +29666,9 @@
     method public boolean performAction(int, android.os.Bundle);
     method public void recycle();
     method public boolean refresh();
+    method public void removeAction(int);
+    method public boolean removeChild(android.view.View);
+    method public boolean removeChild(android.view.View, int);
     method public void setAccessibilityFocused(boolean);
     method public void setBoundsInParent(android.graphics.Rect);
     method public void setBoundsInScreen(android.graphics.Rect);
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index bb04063..7ca3459 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -2272,9 +2272,12 @@
     public static void dumpPackageStateStatic(FileDescriptor fd, String packageName) {
         FileOutputStream fout = new FileOutputStream(fd);
         PrintWriter pw = new FastPrintWriter(fout);
-        dumpService(pw, fd, Context.ACTIVITY_SERVICE, new String[] { "package", packageName });
+        dumpService(pw, fd, Context.ACTIVITY_SERVICE, new String[] {
+                "-a", "package", packageName });
         pw.println();
-        dumpService(pw, fd, ProcessStats.SERVICE_NAME, new String[] { packageName });
+        dumpService(pw, fd, "meminfo", new String[] { "--local", packageName });
+        pw.println();
+        dumpService(pw, fd, ProcessStats.SERVICE_NAME, new String[] { "-a", packageName });
         pw.println();
         dumpService(pw, fd, "usagestats", new String[] { "--packages", packageName });
         pw.println();
@@ -2296,7 +2299,7 @@
             pw.flush();
             tp = new TransferPipe();
             tp.setBufferPrefix("  ");
-            service.dump(tp.getWriteFd().getFileDescriptor(), args);
+            service.dumpAsync(tp.getWriteFd().getFileDescriptor(), args);
             tp.go(fd);
         } catch (Throwable e) {
             if (tp != null) {
diff --git a/core/java/android/app/DownloadManager.java b/core/java/android/app/DownloadManager.java
index b741cc5..2ed8b0f 100644
--- a/core/java/android/app/DownloadManager.java
+++ b/core/java/android/app/DownloadManager.java
@@ -1011,15 +1011,15 @@
     }
 
     /**
-     * Returns {@link Uri} for the given downloaded file id, if the file is
-     * downloaded successfully. otherwise, null is returned.
+     * Returns the {@link Uri} of the given downloaded file id, if the file is
+     * downloaded successfully. Otherwise, null is returned.
      *<p>
      * If the specified downloaded file is in external storage (for example, /sdcard dir),
      * then it is assumed to be safe for anyone to read and the returned {@link Uri} corresponds
      * to the filepath on sdcard.
      *
      * @param id the id of the downloaded file.
-     * @return the {@link Uri} for the given downloaded file id, if download was successful. null
+     * @return the {@link Uri} of the given downloaded file id, if download was successful. null
      * otherwise.
      */
     public Uri getUriForDownloadedFile(long id) {
@@ -1064,15 +1064,11 @@
     }
 
     /**
-     * Returns {@link Uri} for the given downloaded file id, if the file is
-     * downloaded successfully. otherwise, null is returned.
-     *<p>
-     * If the specified downloaded file is in external storage (for example, /sdcard dir),
-     * then it is assumed to be safe for anyone to read and the returned {@link Uri} corresponds
-     * to the filepath on sdcard.
+     * Returns the media type of the given downloaded file id, if the file was
+     * downloaded successfully. Otherwise, null is returned.
      *
      * @param id the id of the downloaded file.
-     * @return the {@link Uri} for the given downloaded file id, if download was successful. null
+     * @return the media type of the given downloaded file id, if download was successful. null
      * otherwise.
      */
     public String getMimeTypeForDownloadedFile(long id) {
diff --git a/core/java/android/app/MediaRouteActionProvider.java b/core/java/android/app/MediaRouteActionProvider.java
index 63b641c..6839c8e 100644
--- a/core/java/android/app/MediaRouteActionProvider.java
+++ b/core/java/android/app/MediaRouteActionProvider.java
@@ -60,7 +60,7 @@
         }
         mRouteTypes = types;
         if (types != 0) {
-            mRouter.addCallback(types, mCallback);
+            mRouter.addCallback(types, mCallback, MediaRouter.CALLBACK_FLAG_PASSIVE_DISCOVERY);
         }
         if (mView != null) {
             mView.setRouteTypes(mRouteTypes);
diff --git a/core/java/android/app/MediaRouteButton.java b/core/java/android/app/MediaRouteButton.java
index 2464e35..e75dc29 100644
--- a/core/java/android/app/MediaRouteButton.java
+++ b/core/java/android/app/MediaRouteButton.java
@@ -128,14 +128,14 @@
 
         if (mToggleMode) {
             if (mRemoteActive) {
-                mRouter.selectRouteInt(mRouteTypes, mRouter.getDefaultRoute());
+                mRouter.selectRouteInt(mRouteTypes, mRouter.getDefaultRoute(), true);
             } else {
                 final int N = mRouter.getRouteCount();
                 for (int i = 0; i < N; i++) {
                     final RouteInfo route = mRouter.getRouteAt(i);
                     if ((route.getSupportedTypes() & mRouteTypes) != 0 &&
                             route != mRouter.getDefaultRoute()) {
-                        mRouter.selectRouteInt(mRouteTypes, route);
+                        mRouter.selectRouteInt(mRouteTypes, route, true);
                     }
                 }
             }
@@ -206,7 +206,8 @@
 
         if (mAttachedToWindow) {
             updateRouteInfo();
-            mRouter.addCallback(types, mRouterCallback);
+            mRouter.addCallback(types, mRouterCallback,
+                    MediaRouter.CALLBACK_FLAG_PASSIVE_DISCOVERY);
         }
     }
 
@@ -222,8 +223,7 @@
     void updateRemoteIndicator() {
         final RouteInfo selected = mRouter.getSelectedRoute(mRouteTypes);
         final boolean isRemote = selected != mRouter.getDefaultRoute();
-        final boolean isConnecting = selected != null &&
-                selected.getStatusCode() == RouteInfo.STATUS_CONNECTING;
+        final boolean isConnecting = selected != null && selected.isConnecting();
 
         boolean needsRefresh = false;
         if (mRemoteActive != isRemote) {
@@ -243,7 +243,7 @@
     void updateRouteCount() {
         final int N = mRouter.getRouteCount();
         int count = 0;
-        boolean hasVideoRoutes = false;
+        boolean scanRequired = false;
         for (int i = 0; i < N; i++) {
             final RouteInfo route = mRouter.getRouteAt(i);
             final int routeTypes = route.getSupportedTypes();
@@ -253,8 +253,9 @@
                 } else {
                     count++;
                 }
-                if ((routeTypes & MediaRouter.ROUTE_TYPE_LIVE_VIDEO) != 0) {
-                    hasVideoRoutes = true;
+                if (((routeTypes & MediaRouter.ROUTE_TYPE_LIVE_VIDEO
+                        | MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY)) != 0) {
+                    scanRequired = true;
                 }
             }
         }
@@ -262,9 +263,10 @@
         setEnabled(count != 0);
 
         // Only allow toggling if we have more than just user routes.
-        // Don't toggle if we support video routes, we may have to let the dialog scan.
-        mToggleMode = count == 2 && (mRouteTypes & MediaRouter.ROUTE_TYPE_LIVE_AUDIO) != 0 &&
-                !hasVideoRoutes;
+        // Don't toggle if we support video or remote display routes, we may have to
+        // let the dialog scan.
+        mToggleMode = count == 2 && (mRouteTypes & MediaRouter.ROUTE_TYPE_LIVE_AUDIO) != 0
+                && !scanRequired;
     }
 
     @Override
@@ -318,7 +320,8 @@
         super.onAttachedToWindow();
         mAttachedToWindow = true;
         if (mRouteTypes != 0) {
-            mRouter.addCallback(mRouteTypes, mRouterCallback);
+            mRouter.addCallback(mRouteTypes, mRouterCallback,
+                    MediaRouter.CALLBACK_FLAG_PASSIVE_DISCOVERY);
             updateRouteInfo();
         }
     }
diff --git a/core/java/android/hardware/camera2/impl/CameraDevice.java b/core/java/android/hardware/camera2/impl/CameraDevice.java
index c428a17..814aa96 100644
--- a/core/java/android/hardware/camera2/impl/CameraDevice.java
+++ b/core/java/android/hardware/camera2/impl/CameraDevice.java
@@ -279,6 +279,10 @@
             checkIfCameraClosed();
             int requestId;
 
+            if (repeating) {
+                stopRepeating();
+            }
+
             try {
                 requestId = mRemoteDevice.submitRequest(request, repeating);
             } catch (CameraRuntimeException e) {
@@ -293,10 +297,6 @@
             }
 
             if (repeating) {
-                // Queue for deletion after in-flight requests finish
-                if (mRepeatingRequestId != REQUEST_ID_NONE) {
-                    mRepeatingRequestIdDeletedList.add(mRepeatingRequestId);
-                }
                 mRepeatingRequestId = requestId;
             }
 
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 447c985..b1a9ea30 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -106,6 +106,11 @@
     public static final int FOREGROUND_ACTIVITY = 10;
 
     /**
+     * A constant indicating a wifi batched scan is active
+     */
+    public static final int WIFI_BATCHED_SCAN = 11;
+
+    /**
      * Include all of the data in the stats, including previously saved data.
      */
     public static final int STATS_SINCE_CHARGED = 0;
@@ -270,6 +275,8 @@
         public abstract void noteFullWifiLockReleasedLocked();
         public abstract void noteWifiScanStartedLocked();
         public abstract void noteWifiScanStoppedLocked();
+        public abstract void noteWifiBatchedScanStartedLocked(int csph);
+        public abstract void noteWifiBatchedScanStoppedLocked();
         public abstract void noteWifiMulticastEnabledLocked();
         public abstract void noteWifiMulticastDisabledLocked();
         public abstract void noteAudioTurnedOnLocked();
@@ -281,6 +288,7 @@
         public abstract long getWifiRunningTime(long batteryRealtime, int which);
         public abstract long getFullWifiLockTime(long batteryRealtime, int which);
         public abstract long getWifiScanTime(long batteryRealtime, int which);
+        public abstract long getWifiBatchedScanTime(int csphBin, long batteryRealtime, int which);
         public abstract long getWifiMulticastTime(long batteryRealtime,
                                                   int which);
         public abstract long getAudioTurnedOnTime(long batteryRealtime, int which);
@@ -288,6 +296,8 @@
         public abstract Timer getForegroundActivityTimer();
         public abstract Timer getVibratorOnTimer();
 
+        public static final int NUM_WIFI_BATCHED_SCAN_BINS = 5;
+
         /**
          * Note that these must match the constants in android.os.PowerManager.
          * Also, if the user activity types change, the BatteryStatsImpl.VERSION must
@@ -2081,9 +2091,11 @@
                                         TimeUtils.formatDuration(ew.usedTime, pw);
                                         pw.print(" over ");
                                         TimeUtils.formatDuration(ew.overTime, pw);
-                                        pw.print(" (");
-                                        pw.print((ew.usedTime*100)/ew.overTime);
-                                        pw.println("%)");
+                                        if (ew.overTime != 0) {
+                                            pw.print(" (");
+                                            pw.print((ew.usedTime*100)/ew.overTime);
+                                            pw.println("%)");
+                                        }
                             }
                         }
                         uidActivity = true;
diff --git a/core/java/android/util/LongArray.java b/core/java/android/util/LongArray.java
new file mode 100644
index 0000000..7d42063
--- /dev/null
+++ b/core/java/android/util/LongArray.java
@@ -0,0 +1,160 @@
+/*
+ * 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 android.util;
+
+import com.android.internal.util.ArrayUtils;
+
+/**
+ * Implements a growing array of long primitives.
+ *
+ * @hide
+ */
+public class LongArray implements Cloneable {
+    private static final int MIN_CAPACITY_INCREMENT = 12;
+
+    private long[] mValues;
+    private int mSize;
+
+    /**
+     * Creates an empty LongArray with the default initial capacity.
+     */
+    public LongArray() {
+        this(10);
+    }
+
+    /**
+     * Creates an empty LongArray with the specified initial capacity.
+     */
+    public LongArray(int initialCapacity) {
+        if (initialCapacity == 0) {
+            mValues = ContainerHelpers.EMPTY_LONGS;
+        } else {
+            initialCapacity = ArrayUtils.idealLongArraySize(initialCapacity);
+            mValues = new long[initialCapacity];
+        }
+        mSize = 0;
+    }
+
+    /**
+     * Appends the specified value to the end of this array.
+     */
+    public void add(long value) {
+        add(mSize, value);
+    }
+
+    /**
+     * Inserts a value at the specified position in this array.
+     *
+     * @throws IndexOutOfBoundsException when index &lt; 0 || index &gt; size()
+     */
+    public void add(int index, long value) {
+        if (index < 0 || index > mSize) {
+            throw new IndexOutOfBoundsException();
+        }
+
+        ensureCapacity(1);
+
+        if (mSize - index != 0) {
+            System.arraycopy(mValues, index, mValues, index + 1, mSize - index);
+        }
+
+        mValues[index] = value;
+        mSize++;
+    }
+
+    /**
+     * Adds the values in the specified array to this array.
+     */
+    public void addAll(LongArray values) {
+        final int count = values.mSize;
+        ensureCapacity(count);
+
+        System.arraycopy(mValues, mSize, values.mValues, 0, count);
+        mSize += count;
+    }
+
+    /**
+     * Ensures capacity to append at least <code>count</code> values.
+     */
+    private void ensureCapacity(int count) {
+        final int currentSize = mSize;
+        final int minCapacity = currentSize + count;
+        if (minCapacity >= mValues.length) {
+            final int targetCap = currentSize + (currentSize < (MIN_CAPACITY_INCREMENT / 2) ?
+                    MIN_CAPACITY_INCREMENT : currentSize >> 1);
+            final int newCapacity = targetCap > minCapacity ? targetCap : minCapacity;
+            final long[] newValues = new long[ArrayUtils.idealLongArraySize(newCapacity)];
+            System.arraycopy(mValues, 0, newValues, 0, currentSize);
+            mValues = newValues;
+        }
+    }
+
+    /**
+     * Removes all values from this array.
+     */
+    public void clear() {
+        mSize = 0;
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public LongArray clone() {
+        LongArray clone = null;
+        try {
+            clone = (LongArray) super.clone();
+            clone.mValues = mValues.clone();
+        } catch (CloneNotSupportedException cnse) {
+            /* ignore */
+        }
+        return clone;
+    }
+
+    /**
+     * Returns the value at the specified position in this array.
+     */
+    public long get(int index) {
+        return mValues[index];
+    }
+
+    /**
+     * Returns the index of the first occurrence of the specified value in this
+     * array, or -1 if this array does not contain the value.
+     */
+    public int indexOf(long value) {
+        final int n = mSize;
+        for (int i = 0; i < n; i++) {
+            if (mValues[i] == value) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * Removes the value at the specified index from this array.
+     */
+    public void remove(int index) {
+        System.arraycopy(mValues, index, mValues, index + 1, mSize - index);
+    }
+
+    /**
+     * Returns the number of values in this array.
+     */
+    public int size() {
+        return mSize;
+    }
+}
diff --git a/core/java/android/view/AccessibilityInteractionController.java b/core/java/android/view/AccessibilityInteractionController.java
index 41d3700..95a13d0 100644
--- a/core/java/android/view/AccessibilityInteractionController.java
+++ b/core/java/android/view/AccessibilityInteractionController.java
@@ -24,6 +24,7 @@
 import android.os.Message;
 import android.os.Process;
 import android.os.RemoteException;
+import android.util.LongArray;
 import android.util.SparseLongArray;
 import android.view.View.AttachInfo;
 import android.view.accessibility.AccessibilityInteractionClient;
@@ -881,13 +882,12 @@
                 AccessibilityNodeInfo parent =
                     provider.createAccessibilityNodeInfo(parentVirtualDescendantId);
                 if (parent != null) {
-                    SparseLongArray childNodeIds = parent.getChildNodeIds();
-                    final int childCount = childNodeIds.size();
+                    final int childCount = parent.getChildCount();
                     for (int i = 0; i < childCount; i++) {
                         if (outInfos.size() >= MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) {
                             return;
                         }
-                        final long childNodeId = childNodeIds.get(i);
+                        final long childNodeId = parent.getChildId(i);
                         if (childNodeId != current.getSourceNodeId()) {
                             final int childVirtualDescendantId =
                                 AccessibilityNodeInfo.getVirtualDescendantId(childNodeId);
@@ -906,14 +906,13 @@
 
         private void prefetchDescendantsOfVirtualNode(AccessibilityNodeInfo root,
                 AccessibilityNodeProvider provider, List<AccessibilityNodeInfo> outInfos) {
-            SparseLongArray childNodeIds = root.getChildNodeIds();
             final int initialOutInfosSize = outInfos.size();
-            final int childCount = childNodeIds.size();
+            final int childCount = root.getChildCount();
             for (int i = 0; i < childCount; i++) {
                 if (outInfos.size() >= MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) {
                     return;
                 }
-                final long childNodeId = childNodeIds.get(i);
+                final long childNodeId = root.getChildId(i);
                 AccessibilityNodeInfo child = provider.createAccessibilityNodeInfo(
                         AccessibilityNodeInfo.getVirtualDescendantId(childNodeId));
                 if (child != null) {
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 27e3b08..d3f63b4 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -645,6 +645,15 @@
                 || uid == 0;
     }
 
+    /**
+     * Returns true if the display is a public presentation display.
+     * @hide
+     */
+    public boolean isPublicPresentation() {
+        return (mFlags & (Display.FLAG_PRIVATE | Display.FLAG_PRESENTATION)) ==
+                Display.FLAG_PRESENTATION;
+    }
+
     private void updateDisplayInfoLocked() {
         // Note: The display manager caches display info objects on our behalf.
         DisplayInfo newInfo = mGlobal.getDisplayInfo(mDisplayId);
diff --git a/core/java/android/view/DisplayList.java b/core/java/android/view/DisplayList.java
index 43fd628..54fb6ef 100644
--- a/core/java/android/view/DisplayList.java
+++ b/core/java/android/view/DisplayList.java
@@ -177,6 +177,20 @@
     public static final int STATUS_DREW = 0x4;
 
     /**
+     * Creates a new display list that can be used to record batches of
+     * drawing operations.
+     *
+     * @param name The name of the display list, used for debugging purpose. May be null.
+     *
+     * @return A new display list.
+     *
+     * @hide
+     */
+    public static DisplayList create(String name) {
+        return new GLES20DisplayList(name);
+    }
+
+    /**
      * Starts recording the display list. All operations performed on the
      * returned canvas are recorded and stored in this display list.
      *
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index f215189..4ddae19 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -66,13 +66,6 @@
     private static final String CACHE_PATH_SHADERS = "com.android.opengl.shaders_cache";
 
     /**
-     * Turn on to only refresh the parts of the screen that need updating.
-     * When turned on the property defined by {@link #RENDER_DIRTY_REGIONS_PROPERTY}
-     * must also have the value "true".
-     */
-    static final boolean RENDER_DIRTY_REGIONS = true;
-
-    /**
      * System property used to enable or disable dirty regions invalidation.
      * This property is only queried if {@link #RENDER_DIRTY_REGIONS} is true.
      * The default value of this property is assumed to be true.
@@ -509,18 +502,6 @@
             Rect dirty);
 
     /**
-     * Creates a new display list that can be used to record batches of
-     * drawing operations.
-     *
-     * @param name The name of the display list, used for debugging purpose. May be null.
-     *
-     * @return A new display list.
-     *
-     * @hide
-     */
-    public abstract DisplayList createDisplayList(String name);
-
-    /**
      * Creates a new hardware layer. A hardware layer built by calling this
      * method will be treated as a texture layer, instead of as a render target.
      *
@@ -853,7 +834,7 @@
         static {
             String dirtyProperty = SystemProperties.get(RENDER_DIRTY_REGIONS_PROPERTY, "true");
             //noinspection PointlessBooleanExpression,ConstantConditions
-            sDirtyRegions = RENDER_DIRTY_REGIONS && "true".equalsIgnoreCase(dirtyProperty);
+            sDirtyRegions = "true".equalsIgnoreCase(dirtyProperty);
             sDirtyRegionsRequested = sDirtyRegions;
         }
 
@@ -2187,11 +2168,6 @@
         }
 
         @Override
-        public DisplayList createDisplayList(String name) {
-            return new GLES20DisplayList(name);
-        }
-
-        @Override
         HardwareLayer createHardwareLayer(boolean isOpaque) {
             return new GLES20TextureLayer(isOpaque);
         }
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 2f1ee67..d8a7efc 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -10946,15 +10946,6 @@
             mPrivateFlags |= PFLAG_DIRTY;
             final ViewParent p = mParent;
             final AttachInfo ai = mAttachInfo;
-            //noinspection PointlessBooleanExpression,ConstantConditions
-            if (!HardwareRenderer.RENDER_DIRTY_REGIONS) {
-                if (p != null && ai != null && ai.mHardwareAccelerated) {
-                    // fast-track for GL-enabled applications; just invalidate the whole hierarchy
-                    // with a null dirty rect, which tells the ViewAncestor to redraw everything
-                    p.invalidateChild(this, null);
-                    return;
-                }
-            }
             if (p != null && ai != null) {
                 final int scrollX = mScrollX;
                 final int scrollY = mScrollY;
@@ -10989,15 +10980,6 @@
             mPrivateFlags |= PFLAG_DIRTY;
             final ViewParent p = mParent;
             final AttachInfo ai = mAttachInfo;
-            //noinspection PointlessBooleanExpression,ConstantConditions
-            if (!HardwareRenderer.RENDER_DIRTY_REGIONS) {
-                if (p != null && ai != null && ai.mHardwareAccelerated) {
-                    // fast-track for GL-enabled applications; just invalidate the whole hierarchy
-                    // with a null dirty rect, which tells the ViewAncestor to redraw everything
-                    p.invalidateChild(this, null);
-                    return;
-                }
-            }
             if (p != null && ai != null && l < r && t < b) {
                 final int scrollX = mScrollX;
                 final int scrollY = mScrollY;
@@ -11045,15 +11027,6 @@
             }
             final AttachInfo ai = mAttachInfo;
             final ViewParent p = mParent;
-            //noinspection PointlessBooleanExpression,ConstantConditions
-            if (!HardwareRenderer.RENDER_DIRTY_REGIONS) {
-                if (p != null && ai != null && ai.mHardwareAccelerated) {
-                    // fast-track for GL-enabled applications; just invalidate the whole hierarchy
-                    // with a null dirty rect, which tells the ViewAncestor to redraw everything
-                    p.invalidateChild(this, null);
-                    return;
-                }
-            }
 
             if (p != null && ai != null) {
                 final Rect r = ai.mTmpInvalRect;
@@ -13433,7 +13406,7 @@
                 mRecreateDisplayList = true;
             }
             if (displayList == null) {
-                displayList = mAttachInfo.mHardwareRenderer.createDisplayList(getClass().getName());
+                displayList = DisplayList.create(getClass().getName());
                 // If we're creating a new display list, make sure our parent gets invalidated
                 // since they will need to recreate their display list to account for this
                 // new child display list.
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 01eec98..dd2baf6 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -2511,13 +2511,13 @@
     void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
         super.onInitializeAccessibilityNodeInfoInternal(info);
         if (mAttachInfo != null) {
-            ArrayList<View> childrenForAccessibility = mAttachInfo.mTempArrayList;
+            final ArrayList<View> childrenForAccessibility = mAttachInfo.mTempArrayList;
             childrenForAccessibility.clear();
             addChildrenForAccessibility(childrenForAccessibility);
             final int childrenForAccessibilityCount = childrenForAccessibility.size();
             for (int i = 0; i < childrenForAccessibilityCount; i++) {
-                View child = childrenForAccessibility.get(i);
-                info.addChild(child);
+                final View child = childrenForAccessibility.get(i);
+                info.addChildUnchecked(child);
             }
             childrenForAccessibility.clear();
         }
diff --git a/core/java/android/view/accessibility/AccessibilityInteractionClient.java b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
index 139df3e..d6e40aec 100644
--- a/core/java/android/view/accessibility/AccessibilityInteractionClient.java
+++ b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
@@ -718,10 +718,9 @@
                 Log.e(LOG_TAG, "Duplicate node.");
                 return;
             }
-            SparseLongArray childIds = current.getChildNodeIds();
-            final int childCount = childIds.size();
+            final int childCount = current.getChildCount();
             for (int i = 0; i < childCount; i++) {
-                final long childId = childIds.valueAt(i);
+                final long childId = current.getChildId(i);
                 for (int j = 0; j < infoCount; j++) {
                     AccessibilityNodeInfo child = infos.get(j);
                     if (child.getSourceNodeId() == childId) {
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 4f53c1e..61aabea 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -22,8 +22,8 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.InputType;
+import android.util.LongArray;
 import android.util.Pools.SynchronizedPool;
-import android.util.SparseLongArray;
 import android.view.View;
 
 import java.util.Collections;
@@ -503,7 +503,7 @@
     private CharSequence mContentDescription;
     private String mViewIdResourceName;
 
-    private final SparseLongArray mChildNodeIds = new SparseLongArray();
+    private LongArray mChildNodeIds;
     private int mActions;
 
     private int mMovementGranularities;
@@ -666,21 +666,35 @@
     }
 
     /**
-     * @return The ids of the children.
+     * Returns the array containing the IDs of this node's children.
      *
      * @hide
      */
-    public SparseLongArray getChildNodeIds() {
+    public LongArray getChildNodeIds() {
         return mChildNodeIds;
     }
 
     /**
+     * Returns the id of the child at the specified index.
+     *
+     * @throws IndexOutOfBoundsException when index &lt; 0 || index &gt;=
+     *             getChildCount()
+     * @hide
+     */
+    public long getChildId(int index) {
+        if (mChildNodeIds == null) {
+            throw new IndexOutOfBoundsException();
+        }
+        return mChildNodeIds.get(index);
+    }
+
+    /**
      * Gets the number of children.
      *
      * @return The child count.
      */
     public int getChildCount() {
-        return mChildNodeIds.size();
+        return mChildNodeIds == null ? 0 : mChildNodeIds.size();
     }
 
     /**
@@ -699,6 +713,9 @@
      */
     public AccessibilityNodeInfo getChild(int index) {
         enforceSealed();
+        if (mChildNodeIds == null) {
+            return null;
+        }
         if (!canPerformRequestOverConnection(mSourceNodeId)) {
             return null;
         }
@@ -721,7 +738,35 @@
      * @throws IllegalStateException If called from an AccessibilityService.
      */
     public void addChild(View child) {
-        addChild(child, UNDEFINED);
+        addChildInternal(child, UNDEFINED, true);
+    }
+
+    /**
+     * Unchecked version of {@link #addChild(View)} that does not verify
+     * uniqueness. For framework use only.
+     *
+     * @hide
+     */
+    public void addChildUnchecked(View child) {
+        addChildInternal(child, UNDEFINED, false);
+    }
+
+    /**
+     * Removes a child. If the child was not previously added to the node,
+     * calling this method has no effect.
+     * <p>
+     * <strong>Note:</strong> Cannot be called from an
+     * {@link android.accessibilityservice.AccessibilityService}.
+     * This class is made immutable before being delivered to an AccessibilityService.
+     * </p>
+     *
+     * @param child The child.
+     * @return true if the child was present
+     *
+     * @throws IllegalStateException If called from an AccessibilityService.
+     */
+    public boolean removeChild(View child) {
+        return removeChild(child, UNDEFINED);
     }
 
     /**
@@ -739,12 +784,49 @@
      * @param virtualDescendantId The id of the virtual child.
      */
     public void addChild(View root, int virtualDescendantId) {
+        addChildInternal(root, virtualDescendantId, true);
+    }
+
+    private void addChildInternal(View root, int virtualDescendantId, boolean checked) {
         enforceNotSealed();
-        final int index = mChildNodeIds.size();
+        if (mChildNodeIds == null) {
+            mChildNodeIds = new LongArray();
+        }
         final int rootAccessibilityViewId =
             (root != null) ? root.getAccessibilityViewId() : UNDEFINED;
         final long childNodeId = makeNodeId(rootAccessibilityViewId, virtualDescendantId);
-        mChildNodeIds.put(index, childNodeId);
+        // If we're checking uniqueness and the ID already exists, abort.
+        if (checked && mChildNodeIds.indexOf(childNodeId) >= 0) {
+            return;
+        }
+        mChildNodeIds.add(childNodeId);
+    }
+
+    /**
+     * Removes a virtual child which is a descendant of the given
+     * <code>root</code>. If the child was not previously added to the node,
+     * calling this method has no effect.
+     *
+     * @param root The root of the virtual subtree.
+     * @param virtualDescendantId The id of the virtual child.
+     * @return true if the child was present
+     * @see #addChild(View, int)
+     */
+    public boolean removeChild(View root, int virtualDescendantId) {
+        enforceNotSealed();
+        final LongArray childIds = mChildNodeIds;
+        if (childIds == null) {
+            return false;
+        }
+        final int rootAccessibilityViewId =
+                (root != null) ? root.getAccessibilityViewId() : UNDEFINED;
+        final long childNodeId = makeNodeId(rootAccessibilityViewId, virtualDescendantId);
+        final int index = childIds.indexOf(childNodeId);
+        if (index < 0) {
+            return false;
+        }
+        childIds.remove(index);
+        return true;
     }
 
     /**
@@ -789,6 +871,24 @@
     }
 
     /**
+     * Removes an action that can be performed on the node. If the action was
+     * not already added to the node, calling this method has no effect.
+     * <p>
+     *   <strong>Note:</strong> Cannot be called from an
+     *   {@link android.accessibilityservice.AccessibilityService}.
+     *   This class is made immutable before being delivered to an AccessibilityService.
+     * </p>
+     *
+     * @param action The action.
+     *
+     * @throws IllegalStateException If called from an AccessibilityService.
+     */
+    public void removeAction(int action) {
+        enforceNotSealed();
+        mActions &= ~action;
+    }
+
+    /**
      * Sets the movement granularities for traversing the text of this node.
      * <p>
      *   <strong>Note:</strong> Cannot be called from an
@@ -1408,8 +1508,6 @@
      *   {@link android.accessibilityservice.AccessibilityService}.
      *   This class is made immutable before being delivered to an AccessibilityService.
      * </p>
-     *
-     * @return collectionItem True if the node is an item.
      */
     public void setCollectionItemInfo(CollectionItemInfo collectionItemInfo) {
         enforceNotSealed();
@@ -1951,6 +2049,7 @@
     /**
      * {@inheritDoc}
      */
+    @Override
     public int describeContents() {
         return 0;
     }
@@ -2114,6 +2213,7 @@
      *      is recycled. You must not touch the object after calling this function.
      * </p>
      */
+    @Override
     public void writeToParcel(Parcel parcel, int flags) {
         parcel.writeInt(isSealed() ? 1 : 0);
         parcel.writeLong(mSourceNodeId);
@@ -2123,11 +2223,15 @@
         parcel.writeLong(mLabeledById);
         parcel.writeInt(mConnectionId);
 
-        SparseLongArray childIds = mChildNodeIds;
-        final int childIdsSize = childIds.size();
-        parcel.writeInt(childIdsSize);
-        for (int i = 0; i < childIdsSize; i++) {
-            parcel.writeLong(childIds.valueAt(i));
+        final LongArray childIds = mChildNodeIds;
+        if (childIds == null) {
+            parcel.writeInt(0);
+        } else {
+            final int childIdsSize = childIds.size();
+            parcel.writeInt(childIdsSize);
+            for (int i = 0; i < childIdsSize; i++) {
+                parcel.writeLong(childIds.get(i));
+            }
         }
 
         parcel.writeInt(mBoundsInParent.top);
@@ -2222,10 +2326,16 @@
         mActions= other.mActions;
         mBooleanProperties = other.mBooleanProperties;
         mMovementGranularities = other.mMovementGranularities;
-        final int otherChildIdCount = other.mChildNodeIds.size();
-        for (int i = 0; i < otherChildIdCount; i++) {
-            mChildNodeIds.put(i, other.mChildNodeIds.valueAt(i));
+
+        final LongArray otherChildNodeIds = other.mChildNodeIds;
+        if (otherChildNodeIds != null && otherChildNodeIds.size() > 0) {
+            if (mChildNodeIds == null) {
+                mChildNodeIds = otherChildNodeIds.clone();
+            } else {
+                mChildNodeIds.addAll(otherChildNodeIds);
+            }
         }
+
         mTextSelectionStart = other.mTextSelectionStart;
         mTextSelectionEnd = other.mTextSelectionEnd;
         mInputType = other.mInputType;
@@ -2255,11 +2365,15 @@
         mLabeledById = parcel.readLong();
         mConnectionId = parcel.readInt();
 
-        SparseLongArray childIds = mChildNodeIds;
         final int childrenSize = parcel.readInt();
-        for (int i = 0; i < childrenSize; i++) {
-            final long childId = parcel.readLong();
-            childIds.put(i, childId);
+        if (childrenSize <= 0) {
+            mChildNodeIds = null;
+        } else {
+            mChildNodeIds = new LongArray(childrenSize);
+            for (int i = 0; i < childrenSize; i++) {
+                final long childId = parcel.readLong();
+                mChildNodeIds.add(childId);
+            }
         }
 
         mBoundsInParent.top = parcel.readInt();
@@ -2331,7 +2445,9 @@
         mWindowId = UNDEFINED;
         mConnectionId = UNDEFINED;
         mMovementGranularities = 0;
-        mChildNodeIds.clear();
+        if (mChildNodeIds != null) {
+            mChildNodeIds.clear();
+        }
         mBoundsInParent.set(0, 0, 0, 0);
         mBoundsInScreen.set(0, 0, 0, 0);
         mBooleanProperties = 0;
@@ -2493,12 +2609,14 @@
             }
             builder.append("]");
 
-            SparseLongArray childIds = mChildNodeIds;
             builder.append("; childAccessibilityIds: [");
-            for (int i = 0, count = childIds.size(); i < count; i++) {
-                builder.append(childIds.valueAt(i));
-                if (i < count - 1) {
-                    builder.append(", ");
+            final LongArray childIds = mChildNodeIds;
+            if (childIds != null) {
+                for (int i = 0, count = childIds.size(); i < count; i++) {
+                    builder.append(childIds.get(i));
+                    if (i < count - 1) {
+                        builder.append(", ");
+                    }
                 }
             }
             builder.append("]");
@@ -2893,16 +3011,18 @@
     }
 
     /**
-     * @see Parcelable.Creator
+     * @see android.os.Parcelable.Creator
      */
     public static final Parcelable.Creator<AccessibilityNodeInfo> CREATOR =
             new Parcelable.Creator<AccessibilityNodeInfo>() {
+        @Override
         public AccessibilityNodeInfo createFromParcel(Parcel parcel) {
             AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
             info.initFromParcel(parcel);
             return info;
         }
 
+        @Override
         public AccessibilityNodeInfo[] newArray(int size) {
             return new AccessibilityNodeInfo[size];
         }
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfoCache.java b/core/java/android/view/accessibility/AccessibilityNodeInfoCache.java
index a9473a8..85aca61 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfoCache.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfoCache.java
@@ -18,6 +18,7 @@
 
 import android.os.Build;
 import android.util.Log;
+import android.util.LongArray;
 import android.util.LongSparseArray;
 import android.util.SparseLongArray;
 
@@ -172,12 +173,12 @@
                     // the new one represents a source state where some of the
                     // children have been removed to avoid having disconnected
                     // subtrees in the cache.
-                    SparseLongArray oldChildrenIds = oldInfo.getChildNodeIds();
-                    SparseLongArray newChildrenIds = info.getChildNodeIds();
-                    final int oldChildCount = oldChildrenIds.size();
+                    // TODO: Runs in O(n^2), could optimize to O(n + n log n)
+                    final LongArray newChildrenIds = info.getChildNodeIds();
+                    final int oldChildCount = oldInfo.getChildCount();
                     for (int i = 0; i < oldChildCount; i++) {
-                        final long oldChildId = oldChildrenIds.valueAt(i);
-                        if (newChildrenIds.indexOfValue(oldChildId) < 0) {
+                        final long oldChildId = oldInfo.getChildId(i);
+                        if (newChildrenIds.indexOf(oldChildId) < 0) {
                             clearSubTreeLocked(oldChildId);
                         }
                     }
@@ -237,10 +238,9 @@
             return;
         }
         mCacheImpl.remove(rootNodeId);
-        SparseLongArray childNodeIds = current.getChildNodeIds();
-        final int childCount = childNodeIds.size();
+        final int childCount = current.getChildCount();
         for (int i = 0; i < childCount; i++) {
-            final long childNodeId = childNodeIds.valueAt(i);
+            final long childNodeId = current.getChildId(i);
             clearSubTreeRecursiveLocked(childNodeId);
         }
     }
@@ -301,11 +301,10 @@
                     }
                 }
 
-                SparseLongArray childIds = current.getChildNodeIds();
-                final int childCount = childIds.size();
+                final int childCount = current.getChildCount();
                 for (int i = 0; i < childCount; i++) {
-                    final long childId = childIds.valueAt(i);
-                    AccessibilityNodeInfo child = mCacheImpl.get(childId);
+                    final long childId = current.getChildId(i);
+                    final AccessibilityNodeInfo child = mCacheImpl.get(childId);
                     if (child != null) {
                         fringe.add(child);
                     }
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index aa3a25d..0e4d422 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -1346,7 +1346,7 @@
                 DisplayList blockDisplayList = mTextDisplayLists[blockIndex];
                 if (blockDisplayList == null) {
                     blockDisplayList = mTextDisplayLists[blockIndex] =
-                            mTextView.getHardwareRenderer().createDisplayList("Text " + blockIndex);
+                            DisplayList.create("Text " + blockIndex);
                 } else {
                     if (blockIsInvalid) blockDisplayList.clear();
                 }
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index 2363062..0771329 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -66,6 +66,8 @@
     void noteFullWifiLockReleasedFromSource(in WorkSource ws);
     void noteWifiScanStartedFromSource(in WorkSource ws);
     void noteWifiScanStoppedFromSource(in WorkSource ws);
+    void noteWifiBatchedScanStartedFromSource(in WorkSource ws, int csph);
+    void noteWifiBatchedScanStoppedFromSource(in WorkSource ws);
     void noteWifiMulticastEnabledFromSource(in WorkSource ws);
     void noteWifiMulticastDisabledFromSource(in WorkSource ws);
     void noteNetworkInterfaceType(String iface, int type);
diff --git a/core/java/com/android/internal/app/MediaRouteChooserDialogFragment.java b/core/java/com/android/internal/app/MediaRouteChooserDialogFragment.java
index e300021..268dcf6 100644
--- a/core/java/com/android/internal/app/MediaRouteChooserDialogFragment.java
+++ b/core/java/com/android/internal/app/MediaRouteChooserDialogFragment.java
@@ -501,7 +501,7 @@
 
                 final RouteInfo route = (RouteInfo) item;
                 if (type == VIEW_ROUTE) {
-                    mRouter.selectRouteInt(mRouteTypes, route);
+                    mRouter.selectRouteInt(mRouteTypes, route, true);
                     dismiss();
                 } else if (type == VIEW_GROUPING_ROUTE) {
                     final Checkable c = (Checkable) view;
@@ -514,7 +514,7 @@
                         if (mRouter.getSelectedRoute(mRouteTypes) == oldGroup) {
                             // Old group was selected but is now empty. Select the group
                             // we're manipulating since that's where the last route went.
-                            mRouter.selectRouteInt(mRouteTypes, mEditingGroup);
+                            mRouter.selectRouteInt(mRouteTypes, mEditingGroup, true);
                         }
                         oldGroup.removeRoute(route);
                         mEditingGroup.addRoute(route);
@@ -555,7 +555,7 @@
                 mEditingGroup = group;
                 mCategoryEditingGroups = group.getCategory();
                 getDialog().setCanceledOnTouchOutside(false);
-                mRouter.selectRouteInt(mRouteTypes, mEditingGroup);
+                mRouter.selectRouteInt(mRouteTypes, mEditingGroup, true);
                 update();
                 scrollToEditingGroup();
             }
diff --git a/core/java/com/android/internal/app/ProcessStats.java b/core/java/com/android/internal/app/ProcessStats.java
index 20b8c95..0cad33c 100644
--- a/core/java/com/android/internal/app/ProcessStats.java
+++ b/core/java/com/android/internal/app/ProcessStats.java
@@ -1758,21 +1758,34 @@
                 mStartTime, now);
         ArrayMap<String, SparseArray<PackageState>> pkgMap = mPackages.getMap();
         boolean printedHeader = false;
+        boolean sepNeeded = false;
         for (int ip=0; ip<pkgMap.size(); ip++) {
-            String pkgName = pkgMap.keyAt(ip);
-            if (reqPackage != null && !reqPackage.equals(pkgName)) {
-                continue;
-            }
-            SparseArray<PackageState> uids = pkgMap.valueAt(ip);
+            final String pkgName = pkgMap.keyAt(ip);
+            final SparseArray<PackageState> uids = pkgMap.valueAt(ip);
             for (int iu=0; iu<uids.size(); iu++) {
-                int uid = uids.keyAt(iu);
-                PackageState pkgState = uids.valueAt(iu);
+                final int uid = uids.keyAt(iu);
+                final PackageState pkgState = uids.valueAt(iu);
                 final int NPROCS = pkgState.mProcesses.size();
                 final int NSRVS = pkgState.mServices.size();
+                final boolean pkgMatch = reqPackage == null || reqPackage.equals(pkgName);
+                if (!pkgMatch) {
+                    boolean procMatch = false;
+                    for (int iproc=0; iproc<NPROCS; iproc++) {
+                        ProcessState proc = pkgState.mProcesses.valueAt(iproc);
+                        if (reqPackage.equals(proc.mName)) {
+                            procMatch = true;
+                            break;
+                        }
+                    }
+                    if (!procMatch) {
+                        continue;
+                    }
+                }
                 if (NPROCS > 0 || NSRVS > 0) {
                     if (!printedHeader) {
                         pw.println("Per-Package Stats:");
                         printedHeader = true;
+                        sepNeeded = true;
                     }
                     pw.print("  * "); pw.print(pkgName); pw.print(" / ");
                             UserHandle.formatUid(pw, uid); pw.println(":");
@@ -1780,6 +1793,9 @@
                 if (!dumpSummary || dumpAll) {
                     for (int iproc=0; iproc<NPROCS; iproc++) {
                         ProcessState proc = pkgState.mProcesses.valueAt(iproc);
+                        if (!pkgMatch && !reqPackage.equals(proc.mName)) {
+                            continue;
+                        }
                         if (activeOnly && !proc.isInUse()) {
                             pw.print("      (Not active: ");
                                     pw.print(pkgState.mProcesses.keyAt(iproc)); pw.println(")");
@@ -1787,7 +1803,11 @@
                         }
                         pw.print("      Process ");
                         pw.print(pkgState.mProcesses.keyAt(iproc));
-                        pw.print(" (");
+                        if (proc.mCommonProcess.mMultiPackage) {
+                            pw.print(" (multi, ");
+                        } else {
+                            pw.print(" (unique, ");
+                        }
                         pw.print(proc.mDurationsTableSize);
                         pw.print(" entries)");
                         pw.println(":");
@@ -1801,6 +1821,9 @@
                     ArrayList<ProcessState> procs = new ArrayList<ProcessState>();
                     for (int iproc=0; iproc<NPROCS; iproc++) {
                         ProcessState proc = pkgState.mProcesses.valueAt(iproc);
+                        if (!pkgMatch && !reqPackage.equals(proc.mName)) {
+                            continue;
+                        }
                         if (activeOnly && !proc.isInUse()) {
                             continue;
                         }
@@ -1811,6 +1834,9 @@
                 }
                 for (int isvc=0; isvc<NSRVS; isvc++) {
                     ServiceState svc = pkgState.mServices.valueAt(isvc);
+                    if (!pkgMatch && !reqPackage.equals(svc.mProcessName)) {
+                        continue;
+                    }
                     if (activeOnly && !svc.isInUse()) {
                         pw.print("      (Not active: ");
                                 pw.print(pkgState.mServices.keyAt(isvc)); pw.println(")");
@@ -1840,64 +1866,73 @@
                         if (svc.mOwner != null) {
                             pw.print("        mOwner="); pw.println(svc.mOwner);
                         }
+                        if (svc.mStarted || svc.mRestarting) {
+                            pw.print("        mStarted="); pw.print(svc.mStarted);
+                            pw.print(" mRestarting="); pw.println(svc.mRestarting);
+                        }
                     }
                 }
             }
         }
 
-        if (reqPackage == null) {
-            ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap();
-            printedHeader = false;
-            int numShownProcs = 0, numTotalProcs = 0;
-            for (int ip=0; ip<procMap.size(); ip++) {
-                String procName = procMap.keyAt(ip);
-                SparseArray<ProcessState> uids = procMap.valueAt(ip);
-                for (int iu=0; iu<uids.size(); iu++) {
-                    int uid = uids.keyAt(iu);
-                    numTotalProcs++;
-                    ProcessState proc = uids.valueAt(iu);
-                    if (proc.mDurationsTableSize == 0 && proc.mCurState == STATE_NOTHING
-                            && proc.mPssTableSize == 0) {
-                        continue;
-                    }
-                    numShownProcs++;
-                    if (!printedHeader) {
-                        pw.println();
-                        pw.println("Per-Process Stats:");
-                        printedHeader = true;
-                    }
-                    if (activeOnly && !proc.isInUse()) {
-                        pw.print("      (Not active: "); pw.print(procName); pw.println(")");
-                        continue;
-                    }
-                    pw.print("  * "); pw.print(procName); pw.print(" / ");
-                            UserHandle.formatUid(pw, uid);
-                            pw.print(" ("); pw.print(proc.mDurationsTableSize);
-                            pw.print(" entries)"); pw.println(":");
-                    dumpProcessState(pw, "        ", proc, ALL_SCREEN_ADJ, ALL_MEM_ADJ,
-                            ALL_PROC_STATES, now);
-                    dumpProcessPss(pw, "        ", proc, ALL_SCREEN_ADJ, ALL_MEM_ADJ,
-                            ALL_PROC_STATES);
-                    if (dumpAll) {
-                        dumpProcessInternalLocked(pw, "        ", proc, dumpAll);
-                    }
+        ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap();
+        printedHeader = false;
+        int numShownProcs = 0, numTotalProcs = 0;
+        for (int ip=0; ip<procMap.size(); ip++) {
+            String procName = procMap.keyAt(ip);
+            SparseArray<ProcessState> uids = procMap.valueAt(ip);
+            for (int iu=0; iu<uids.size(); iu++) {
+                int uid = uids.keyAt(iu);
+                numTotalProcs++;
+                ProcessState proc = uids.valueAt(iu);
+                if (proc.mDurationsTableSize == 0 && proc.mCurState == STATE_NOTHING
+                        && proc.mPssTableSize == 0) {
+                    continue;
                 }
+                if (!proc.mMultiPackage) {
+                    continue;
+                }
+                if (reqPackage != null && !reqPackage.equals(procName)
+                        && !reqPackage.equals(proc.mPackage)) {
+                    continue;
+                }
+                numShownProcs++;
+                if (sepNeeded) {
+                    pw.println();
+                }
+                sepNeeded = true;
+                if (!printedHeader) {
+                    pw.println("Multi-Package Common Processes:");
+                    printedHeader = true;
+                }
+                if (activeOnly && !proc.isInUse()) {
+                    pw.print("      (Not active: "); pw.print(procName); pw.println(")");
+                    continue;
+                }
+                pw.print("  * "); pw.print(procName); pw.print(" / ");
+                        UserHandle.formatUid(pw, uid);
+                        pw.print(" ("); pw.print(proc.mDurationsTableSize);
+                        pw.print(" entries)"); pw.println(":");
+                dumpProcessState(pw, "        ", proc, ALL_SCREEN_ADJ, ALL_MEM_ADJ,
+                        ALL_PROC_STATES, now);
+                dumpProcessPss(pw, "        ", proc, ALL_SCREEN_ADJ, ALL_MEM_ADJ,
+                        ALL_PROC_STATES);
+                dumpProcessInternalLocked(pw, "        ", proc, dumpAll);
             }
-            if (dumpAll) {
-                pw.println();
-                pw.print("  Total procs: "); pw.print(numShownProcs);
-                        pw.print(" shown of "); pw.print(numTotalProcs); pw.println(" total");
-            }
+        }
+        if (dumpAll) {
+            pw.println();
+            pw.print("  Total procs: "); pw.print(numShownProcs);
+                    pw.print(" shown of "); pw.print(numTotalProcs); pw.println(" total");
+        }
 
+        if (sepNeeded) {
             pw.println();
-            if (dumpSummary) {
-                pw.println("Summary:");
-                dumpSummaryLocked(pw, reqPackage, now, activeOnly);
-            } else {
-                dumpTotalsLocked(pw, now);
-            }
+        }
+        if (dumpSummary) {
+            pw.println("Summary:");
+            dumpSummaryLocked(pw, reqPackage, now, activeOnly);
         } else {
-            pw.println();
             dumpTotalsLocked(pw, now);
         }
 
@@ -2031,17 +2066,20 @@
     public ArrayList<ProcessState> collectProcessesLocked(int[] screenStates, int[] memStates,
             int[] procStates, int sortProcStates[], long now, String reqPackage,
             boolean activeOnly) {
-        ArraySet<ProcessState> foundProcs = new ArraySet<ProcessState>();
-        ArrayMap<String, SparseArray<PackageState>> pkgMap = mPackages.getMap();
+        final ArraySet<ProcessState> foundProcs = new ArraySet<ProcessState>();
+        final ArrayMap<String, SparseArray<PackageState>> pkgMap = mPackages.getMap();
         for (int ip=0; ip<pkgMap.size(); ip++) {
-            if (reqPackage != null && !reqPackage.equals(pkgMap.keyAt(ip))) {
-                continue;
-            }
-            SparseArray<PackageState> procs = pkgMap.valueAt(ip);
+            final String pkgName = pkgMap.keyAt(ip);
+            final SparseArray<PackageState> procs = pkgMap.valueAt(ip);
             for (int iu=0; iu<procs.size(); iu++) {
-                PackageState state = procs.valueAt(iu);
-                for (int iproc=0; iproc<state.mProcesses.size(); iproc++) {
-                    ProcessState proc = state.mProcesses.valueAt(iproc);
+                final PackageState state = procs.valueAt(iu);
+                final int NPROCS = state.mProcesses.size();
+                final boolean pkgMatch = reqPackage == null || reqPackage.equals(pkgName);
+                for (int iproc=0; iproc<NPROCS; iproc++) {
+                    final ProcessState proc = state.mProcesses.valueAt(iproc);
+                    if (!pkgMatch && !reqPackage.equals(proc.mName)) {
+                        continue;
+                    }
                     if (activeOnly && !proc.isInUse()) {
                         continue;
                     }
@@ -2601,23 +2639,35 @@
             }
         }
 
-        void incStartedServices(int memFactor, long now) {
+        void incStartedServices(int memFactor, long now, String serviceName) {
+            if (false) {
+                RuntimeException here = new RuntimeException("here");
+                here.fillInStackTrace();
+                Slog.d(TAG, "incStartedServices: " + this + " service=" + serviceName
+                        + " to " + (mNumStartedServices+1), here);
+            }
             if (mCommonProcess != this) {
-                mCommonProcess.incStartedServices(memFactor, now);
+                mCommonProcess.incStartedServices(memFactor, now, serviceName);
             }
             mNumStartedServices++;
             if (mNumStartedServices == 1 && mCurState == STATE_NOTHING) {
-                setState(STATE_NOTHING, memFactor, now, null);
+                setState(STATE_SERVICE_RESTARTING + (memFactor*STATE_COUNT), now);
             }
         }
 
-        void decStartedServices(int memFactor, long now) {
+        void decStartedServices(int memFactor, long now, String serviceName) {
+            if (false) {
+                RuntimeException here = new RuntimeException("here");
+                here.fillInStackTrace();
+                Slog.d(TAG, "decActiveServices: " + this + " service=" + serviceName
+                        + " to " + (mNumStartedServices-1), here);
+            }
             if (mCommonProcess != this) {
-                mCommonProcess.decStartedServices(memFactor, now);
+                mCommonProcess.decStartedServices(memFactor, now, serviceName);
             }
             mNumStartedServices--;
-            if (mNumStartedServices == 0 && mCurState == STATE_SERVICE_RESTARTING) {
-                setState(STATE_NOTHING, memFactor, now, null);
+            if (mNumStartedServices == 0 && (mCurState%STATE_COUNT) == STATE_SERVICE_RESTARTING) {
+                setState(STATE_NOTHING, now);
             } else if (mNumStartedServices < 0) {
                 Slog.wtfStack(TAG, "Proc started services underrun: pkg="
                         + mPackage + " uid=" + mUid + " name=" + mName);
@@ -2873,6 +2923,8 @@
         public int mRunState = STATE_NOTHING;
         long mRunStartTime;
 
+        boolean mStarted;
+        boolean mRestarting;
         int mStartedCount;
         public int mStartedState = STATE_NOTHING;
         long mStartedStartTime;
@@ -2902,10 +2954,9 @@
                     // There was already an old owner, reset this object for its
                     // new owner.
                     mOwner = newOwner;
-                    if (mStartedState != STATE_NOTHING || mBoundState != STATE_NOTHING
-                            || mExecState != STATE_NOTHING) {
+                    if (mStarted || mBoundState != STATE_NOTHING || mExecState != STATE_NOTHING) {
                         long now = SystemClock.uptimeMillis();
-                        if (mStartedState != STATE_NOTHING) {
+                        if (mStarted) {
                             if (DEBUG) Slog.d(TAG, "Service has new owner " + newOwner
                                     + " from " + mOwner + " while started: pkg="
                                     + mPackage + " service=" + mName + " proc=" + mProc);
@@ -2931,10 +2982,9 @@
         public void clearCurrentOwner(Object owner, boolean silently) {
             if (mOwner == owner) {
                 mProc.decActiveServices(mName);
-                if (mStartedState != STATE_NOTHING || mBoundState != STATE_NOTHING
-                        || mExecState != STATE_NOTHING) {
+                if (mStarted || mBoundState != STATE_NOTHING || mExecState != STATE_NOTHING) {
                     long now = SystemClock.uptimeMillis();
-                    if (mStartedState != STATE_NOTHING) {
+                    if (mStarted) {
                         if (!silently) {
                             Slog.wtfStack(TAG, "Service owner " + owner
                                     + " cleared while started: pkg=" + mPackage + " service="
@@ -3042,7 +3092,18 @@
             if (mOwner == null) {
                 Slog.wtf(TAG, "Starting service " + this + " without owner");
             }
+            mStarted = started;
+            updateStartedState(memFactor, now);
+        }
+
+        public void setRestarting(boolean restarting, int memFactor, long now) {
+            mRestarting = restarting;
+            updateStartedState(memFactor, now);
+        }
+
+        void updateStartedState(int memFactor, long now) {
             final boolean wasStarted = mStartedState != STATE_NOTHING;
+            final boolean started = mStarted || mRestarting;
             final int state = started ? memFactor : STATE_NOTHING;
             if (mStartedState != state) {
                 if (mStartedState != STATE_NOTHING) {
@@ -3056,9 +3117,9 @@
                 mProc = mProc.pullFixedProc(mPackage);
                 if (wasStarted != started) {
                     if (started) {
-                        mProc.incStartedServices(memFactor, now);
+                        mProc.incStartedServices(memFactor, now, mName);
                     } else {
-                        mProc.decStartedServices(memFactor, now);
+                        mProc.decStartedServices(memFactor, now, mName);
                     }
                 }
                 updateRunning(memFactor, now);
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index da12d91..2e5fcec 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -154,6 +154,8 @@
     final ArrayList<StopwatchTimer> mFullWifiLockTimers = new ArrayList<StopwatchTimer>();
     final ArrayList<StopwatchTimer> mWifiMulticastTimers = new ArrayList<StopwatchTimer>();
     final ArrayList<StopwatchTimer> mWifiScanTimers = new ArrayList<StopwatchTimer>();
+    final SparseArray<ArrayList<StopwatchTimer>> mWifiBatchedScanTimers =
+            new SparseArray<ArrayList<StopwatchTimer>>();
 
     // Last partial timers we use for distributing CPU usage.
     final ArrayList<StopwatchTimer> mLastPartialTimers = new ArrayList<StopwatchTimer>();
@@ -2404,6 +2406,14 @@
         getUidStatsLocked(uid).noteWifiScanStoppedLocked();
     }
 
+    public void noteWifiBatchedScanStartedLocked(int uid, int csph) {
+        getUidStatsLocked(uid).noteWifiBatchedScanStartedLocked(csph);
+    }
+
+    public void noteWifiBatchedScanStoppedLocked(int uid) {
+        getUidStatsLocked(uid).noteWifiBatchedScanStoppedLocked();
+    }
+
     int mWifiMulticastNesting = 0;
 
     public void noteWifiMulticastEnabledLocked(int uid) {
@@ -2456,6 +2466,20 @@
         }
     }
 
+    public void noteWifiBatchedScanStartedFromSourceLocked(WorkSource ws, int csph) {
+        int N = ws.size();
+        for (int i=0; i<N; i++) {
+            noteWifiBatchedScanStartedLocked(ws.get(i), csph);
+        }
+    }
+
+    public void noteWifiBatchedScanStoppedFromSourceLocked(WorkSource ws) {
+        int N = ws.size();
+        for (int i=0; i<N; i++) {
+            noteWifiBatchedScanStoppedLocked(ws.get(i));
+        }
+    }
+
     public void noteWifiMulticastEnabledFromSourceLocked(WorkSource ws) {
         int N = ws.size();
         for (int i=0; i<N; i++) {
@@ -2579,6 +2603,10 @@
         boolean mWifiScanStarted;
         StopwatchTimer mWifiScanTimer;
 
+        private static final int NO_BATCHED_SCAN_STARTED = -1;
+        int mWifiBatchedScanBinStarted = NO_BATCHED_SCAN_STARTED;
+        StopwatchTimer[] mWifiBatchedScanTimer;
+
         boolean mWifiMulticastEnabled;
         StopwatchTimer mWifiMulticastTimer;
 
@@ -2629,6 +2657,7 @@
                     mFullWifiLockTimers, mUnpluggables);
             mWifiScanTimer = new StopwatchTimer(Uid.this, WIFI_SCAN,
                     mWifiScanTimers, mUnpluggables);
+            mWifiBatchedScanTimer = new StopwatchTimer[NUM_WIFI_BATCHED_SCAN_BINS];
             mWifiMulticastTimer = new StopwatchTimer(Uid.this, WIFI_MULTICAST_ENABLED,
                     mWifiMulticastTimers, mUnpluggables);
         }
@@ -2719,6 +2748,36 @@
         }
 
         @Override
+        public void noteWifiBatchedScanStartedLocked(int csph) {
+            int bin = 0;
+            while (csph > 8 && bin < NUM_WIFI_BATCHED_SCAN_BINS) {
+                csph = csph >> 3;
+                bin++;
+            }
+
+            if (mWifiBatchedScanBinStarted == bin) return;
+
+            if (mWifiBatchedScanBinStarted != NO_BATCHED_SCAN_STARTED) {
+                mWifiBatchedScanTimer[mWifiBatchedScanBinStarted].
+                        stopRunningLocked(BatteryStatsImpl.this);
+            }
+            mWifiBatchedScanBinStarted = bin;
+            if (mWifiBatchedScanTimer[bin] == null) {
+                makeWifiBatchedScanBin(bin, null);
+            }
+            mWifiBatchedScanTimer[bin].startRunningLocked(BatteryStatsImpl.this);
+        }
+
+        @Override
+        public void noteWifiBatchedScanStoppedLocked() {
+            if (mWifiBatchedScanBinStarted != NO_BATCHED_SCAN_STARTED) {
+                mWifiBatchedScanTimer[mWifiBatchedScanBinStarted].
+                        stopRunningLocked(BatteryStatsImpl.this);
+                mWifiBatchedScanBinStarted = NO_BATCHED_SCAN_STARTED;
+            }
+        }
+
+        @Override
         public void noteWifiMulticastEnabledLocked() {
             if (!mWifiMulticastEnabled) {
                 mWifiMulticastEnabled = true;
@@ -2854,6 +2913,15 @@
         }
 
         @Override
+        public long getWifiBatchedScanTime(int csphBin, long batteryRealtime, int which) {
+            if (csphBin < 0 || csphBin >= NUM_WIFI_BATCHED_SCAN_BINS) return 0;
+            if (mWifiBatchedScanTimer[csphBin] == null) {
+                return 0;
+            }
+            return mWifiBatchedScanTimer[csphBin].getTotalTimeLocked(batteryRealtime, which);
+        }
+
+        @Override
         public long getWifiMulticastTime(long batteryRealtime, int which) {
             if (mWifiMulticastTimer == null) {
                 return 0;
@@ -2914,6 +2982,24 @@
             return mUserActivityCounters[type].getCountLocked(which);
         }
 
+        void makeWifiBatchedScanBin(int i, Parcel in) {
+            if (i < 0 || i >= NUM_WIFI_BATCHED_SCAN_BINS) return;
+
+            ArrayList<StopwatchTimer> collected = mWifiBatchedScanTimers.get(i);
+            if (collected == null) {
+                collected = new ArrayList<StopwatchTimer>();
+                mWifiBatchedScanTimers.put(i, collected);
+            }
+            if (in == null) {
+                mWifiBatchedScanTimer[i] = new StopwatchTimer(this, WIFI_BATCHED_SCAN, collected,
+                        mUnpluggables);
+            } else {
+                mWifiBatchedScanTimer[i] = new StopwatchTimer(this, WIFI_BATCHED_SCAN, collected,
+                        mUnpluggables, in);
+            }
+        }
+
+
         void initUserActivityLocked() {
             mUserActivityCounters = new Counter[NUM_USER_ACTIVITY_TYPES];
             for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
@@ -2974,6 +3060,14 @@
                 active |= !mWifiScanTimer.reset(BatteryStatsImpl.this, false);
                 active |= mWifiScanStarted;
             }
+            if (mWifiBatchedScanTimer != null) {
+                for (int i = 0; i < NUM_WIFI_BATCHED_SCAN_BINS; i++) {
+                    if (mWifiBatchedScanTimer[i] != null) {
+                        active |= !mWifiBatchedScanTimer[i].reset(BatteryStatsImpl.this, false);
+                    }
+                }
+                active |= (mWifiBatchedScanBinStarted != NO_BATCHED_SCAN_STARTED);
+            }
             if (mWifiMulticastTimer != null) {
                 active |= !mWifiMulticastTimer.reset(BatteryStatsImpl.this, false);
                 active |= mWifiMulticastEnabled;
@@ -3080,6 +3174,11 @@
                 if (mWifiScanTimer != null) {
                     mWifiScanTimer.detach();
                 }
+                for (int i = 0; i < NUM_WIFI_BATCHED_SCAN_BINS; i++) {
+                    if (mWifiBatchedScanTimer[i] != null) {
+                        mWifiBatchedScanTimer[i].detach();
+                    }
+                }
                 if (mWifiMulticastTimer != null) {
                     mWifiMulticastTimer.detach();
                 }
@@ -3157,6 +3256,14 @@
             } else {
                 out.writeInt(0);
             }
+            for (int i = 0; i < NUM_WIFI_BATCHED_SCAN_BINS; i++) {
+                if (mWifiBatchedScanTimer[i] != null) {
+                    out.writeInt(1);
+                    mWifiBatchedScanTimer[i].writeToParcel(out, batteryRealtime);
+                } else {
+                    out.writeInt(0);
+                }
+            }
             if (mWifiMulticastTimer != null) {
                 out.writeInt(1);
                 mWifiMulticastTimer.writeToParcel(out, batteryRealtime);
@@ -3266,6 +3373,14 @@
             } else {
                 mWifiScanTimer = null;
             }
+            mWifiBatchedScanBinStarted = NO_BATCHED_SCAN_STARTED;
+            for (int i = 0; i < NUM_WIFI_BATCHED_SCAN_BINS; i++) {
+                if (in.readInt() != 0) {
+                    makeWifiBatchedScanBin(i, in);
+                } else {
+                    mWifiBatchedScanTimer[i] = null;
+                }
+            }
             mWifiMulticastEnabled = false;
             if (in.readInt() != 0) {
                 mWifiMulticastTimer = new StopwatchTimer(Uid.this, WIFI_MULTICAST_ENABLED,
@@ -5463,6 +5578,13 @@
             if (in.readInt() != 0) {
                 u.mWifiScanTimer.readSummaryFromParcelLocked(in);
             }
+            u.mWifiBatchedScanBinStarted = Uid.NO_BATCHED_SCAN_STARTED;
+            for (int i = 0; i < Uid.NUM_WIFI_BATCHED_SCAN_BINS; i++) {
+                if (in.readInt() != 0) {
+                    u.makeWifiBatchedScanBin(i, null);
+                    u.mWifiBatchedScanTimer[i].readSummaryFromParcelLocked(in);
+                }
+            }
             u.mWifiMulticastEnabled = false;
             if (in.readInt() != 0) {
                 u.mWifiMulticastTimer.readSummaryFromParcelLocked(in);
@@ -5674,6 +5796,14 @@
             } else {
                 out.writeInt(0);
             }
+            for (int i = 0; i < Uid.NUM_WIFI_BATCHED_SCAN_BINS; i++) {
+                if (u.mWifiBatchedScanTimer[i] != null) {
+                    out.writeInt(1);
+                    u.mWifiBatchedScanTimer[i].writeSummaryFromParcelLocked(out, NOWREAL);
+                } else {
+                    out.writeInt(0);
+                }
+            }
             if (u.mWifiMulticastTimer != null) {
                 out.writeInt(1);
                 u.mWifiMulticastTimer.writeSummaryFromParcelLocked(out, NOWREAL);
@@ -5909,6 +6039,7 @@
         mWifiRunningTimers.clear();
         mFullWifiLockTimers.clear();
         mWifiScanTimers.clear();
+        mWifiBatchedScanTimers.clear();
         mWifiMulticastTimers.clear();
 
         sNumSpeedSteps = in.readInt();
diff --git a/core/java/com/android/internal/os/PowerProfile.java b/core/java/com/android/internal/os/PowerProfile.java
index 99a6843..94750d3 100644
--- a/core/java/com/android/internal/os/PowerProfile.java
+++ b/core/java/com/android/internal/os/PowerProfile.java
@@ -136,6 +136,13 @@
     public static final String POWER_CPU_SPEEDS = "cpu.speeds";
 
     /**
+     * Power consumed by wif batched scaning.  Broken down into bins by
+     * Channels Scanned per Hour.  May do 1-720 scans per hour of 1-100 channels
+     * for a range of 1-72,000.  Going logrithmic (1-8, 9-64, 65-512, 513-4096, 4097-)!
+     */
+    public static final String POWER_WIFI_BATCHED_SCAN = "wifi.batchedscan";
+
+    /**
      * Battery capacity in milliAmpHour (mAh).
      */
     public static final String POWER_BATTERY_CAPACITY = "battery.capacity";
@@ -171,7 +178,7 @@
 
                 String element = parser.getName();
                 if (element == null) break;
-                
+
                 if (parsingArray && !element.equals(TAG_ARRAYITEM)) {
                     // Finish array
                     sPowerMap.put(arrayName, array.toArray(new Double[array.size()]));
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index 3381959..4f3b5b3 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -197,10 +197,14 @@
 
         try {
             parsedArgs = new Arguments(args);
+            if (parsedArgs.permittedCapabilities != 0 || parsedArgs.effectiveCapabilities != 0) {
+                throw new ZygoteSecurityException("Client may not specify capabilities: " +
+                        "permitted=0x" + Long.toHexString(parsedArgs.permittedCapabilities) +
+                        ", effective=0x" + Long.toHexString(parsedArgs.effectiveCapabilities));
+            }
 
             applyUidSecurityPolicy(parsedArgs, peer, peerSecurityContext);
             applyRlimitSecurityPolicy(parsedArgs, peer, peerSecurityContext);
-            applyCapabilitiesSecurityPolicy(parsedArgs, peer, peerSecurityContext);
             applyInvokeWithSecurityPolicy(parsedArgs, peer, peerSecurityContext);
             applyseInfoSecurityPolicy(parsedArgs, peer, peerSecurityContext);
 
@@ -703,71 +707,6 @@
     }
 
     /**
-     * Applies zygote security policy per bug #1042973. A root peer may
-     * spawn an instance with any capabilities. All other uids may spawn
-     * instances with any of the capabilities in the peer's permitted set
-     * but no more.
-     *
-     * @param args non-null; zygote spawner arguments
-     * @param peer non-null; peer credentials
-     * @throws ZygoteSecurityException
-     */
-    private static void applyCapabilitiesSecurityPolicy(
-            Arguments args, Credentials peer, String peerSecurityContext)
-            throws ZygoteSecurityException {
-
-        if (args.permittedCapabilities == 0
-                && args.effectiveCapabilities == 0) {
-            // nothing to check
-            return;
-        }
-
-        boolean allowed = SELinux.checkSELinuxAccess(peerSecurityContext,
-                                                     peerSecurityContext,
-                                                     "zygote",
-                                                     "specifycapabilities");
-        if (!allowed) {
-            throw new ZygoteSecurityException(
-                    "Peer may not specify capabilities");
-        }
-
-        if (peer.getUid() == 0) {
-            // root may specify anything
-            return;
-        }
-
-        long permittedCaps;
-
-        try {
-            permittedCaps = ZygoteInit.capgetPermitted(peer.getPid());
-        } catch (IOException ex) {
-            throw new ZygoteSecurityException(
-                    "Error retrieving peer's capabilities.");
-        }
-
-        /*
-         * Ensure that the client did not specify an effective set larger
-         * than the permitted set. The kernel will enforce this too, but we
-         * do it here to make the following check easier.
-         */
-        if (((~args.permittedCapabilities) & args.effectiveCapabilities) != 0) {
-            throw new ZygoteSecurityException(
-                    "Effective capabilities cannot be superset of "
-                            + " permitted capabilities" );
-        }
-
-        /*
-         * Ensure that the new permitted (and thus the new effective) set is
-         * a subset of the peer process's permitted set
-         */
-
-        if (((~permittedCaps) & args.permittedCapabilities) != 0) {
-            throw new ZygoteSecurityException(
-                    "Peer specified unpermitted capabilities" );
-        }
-    }
-
-    /**
      * Applies zygote security policy.
      * Based on the credentials of the process issuing a zygote command:
      * <ol>
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index a7faadf..48092f6 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -723,15 +723,6 @@
             throws IOException;
 
     /**
-     * Retrieves the permitted capability set from another process.
-     *
-     * @param pid &gt;=0 process ID or 0 for this process
-     * @throws IOException on error
-     */
-    static native long capgetPermitted(int pid)
-            throws IOException;
-
-    /**
      * Invokes select() on the provider array of file descriptors (selecting
      * for readability only). Array elements of null are ignored.
      *
diff --git a/core/jni/android/graphics/pdf/PdfDocument.cpp b/core/jni/android/graphics/pdf/PdfDocument.cpp
index b57a0fe..6175a8f 100644
--- a/core/jni/android/graphics/pdf/PdfDocument.cpp
+++ b/core/jni/android/graphics/pdf/PdfDocument.cpp
@@ -17,62 +17,138 @@
 #include "jni.h"
 #include "GraphicsJNI.h"
 #include <android_runtime/AndroidRuntime.h>
+#include <vector>
+
+#include "CreateJavaOutputStreamAdaptor.h"
 
 #include "SkCanvas.h"
-#include "SkPDFDevice.h"
-#include "SkPDFDocument.h"
+#include "SkDocument.h"
+#include "SkPicture.h"
+#include "SkStream.h"
 #include "SkRect.h"
-#include "SkSize.h"
-#include "CreateJavaOutputStreamAdaptor.h"
-#include "JNIHelp.h"
 
 namespace android {
 
-#define LOGD(x...) do { Log::Instance()->printf(Log::ELogD, x); } while(0)
+struct PageRecord {
 
-static jint nativeCreateDocument(JNIEnv* env, jobject clazz) {
-    return reinterpret_cast<jint>(new SkPDFDocument());
+    PageRecord(int width, int height, const SkRect& contentRect)
+            : mPicture(new SkPicture()), mWidth(width), mHeight(height) {
+        mContentRect = contentRect;
+    }
+
+    ~PageRecord() {
+        mPicture->unref();
+    }
+
+    SkPicture* const mPicture;
+    const int mWidth;
+    const int mHeight;
+    SkRect mContentRect;
+};
+
+class PdfDocument {
+public:
+    PdfDocument() {
+        mCurrentPage = NULL;
+    }
+
+    SkCanvas* startPage(int width, int height,
+            int contentLeft, int contentTop, int contentRight, int contentBottom) {
+        assert(mCurrentPage == NULL);
+
+        SkRect contentRect = SkRect::MakeLTRB(
+                contentLeft, contentTop, contentRight, contentBottom);
+        PageRecord* page = new PageRecord(width, height, contentRect);
+        mPages.push_back(page);
+        mCurrentPage = page;
+
+        SkCanvas* canvas = page->mPicture->beginRecording(
+                contentRect.width(), contentRect.height(), 0);
+
+        // We pass this canvas to Java where it is used to construct
+        // a Java Canvas object which dereferences the pointer when it
+        // is destroyed, so we have to bump up the reference count.
+        canvas->ref();
+
+        return canvas;
+    }
+
+    void finishPage() {
+        assert(mCurrentPage != NULL);
+        mCurrentPage->mPicture->endRecording();
+        mCurrentPage = NULL;
+    }
+
+    void write(SkWStream* stream) {
+        SkDocument* document = SkDocument::CreatePDF(stream);
+        for (unsigned i = 0; i < mPages.size(); i++) {
+            PageRecord* page =  mPages[i];
+
+            SkCanvas* canvas = document->beginPage(page->mWidth, page->mHeight,
+                    &(page->mContentRect));
+
+            canvas->clipRect(page->mContentRect);
+            canvas->translate(page->mContentRect.left(), page->mContentRect.top());
+            canvas->drawPicture(*page->mPicture);
+
+            document->endPage();
+        }
+        document->close();
+    }
+
+    void close() {
+        for (unsigned i = 0; i < mPages.size(); i++) {
+            delete mPages[i];
+        }
+        delete mCurrentPage;
+        mCurrentPage = NULL;
+    }
+
+private:
+    ~PdfDocument() {
+        close();
+    }
+
+    std::vector<PageRecord*> mPages;
+    PageRecord* mCurrentPage;
+};
+
+static jint nativeCreateDocument(JNIEnv* env, jobject thiz) {
+    return reinterpret_cast<jint>(new PdfDocument());
 }
 
-static void nativeFinalize(JNIEnv* env, jobject thiz, jint documentPtr) {
-    delete reinterpret_cast<SkPDFDocument*>(documentPtr);
-}
-
-static jint nativeCreatePage(JNIEnv* env, jobject thiz, jint pageWidth, jint pageHeight,
+static jint nativeStartPage(JNIEnv* env, jobject thiz, jint documentPtr,
+        jint pageWidth, jint pageHeight,
         jint contentLeft, jint contentTop, jint contentRight, jint contentBottom) {
-
-    SkMatrix transformation;
-    transformation.setTranslate(contentLeft, contentTop);
-
-    SkISize skPageSize = SkISize::Make(pageWidth, pageHeight);
-    SkISize skContentSize = SkISize::Make(contentRight - contentLeft, contentBottom - contentTop);
-
-    SkPDFDevice* skPdfDevice = new SkPDFDevice(skPageSize, skContentSize, transformation);
-    return reinterpret_cast<jint>(new SkCanvas(skPdfDevice));
+    PdfDocument* document = reinterpret_cast<PdfDocument*>(documentPtr);
+    return reinterpret_cast<jint>(document->startPage(pageWidth, pageHeight,
+            contentLeft, contentTop, contentRight, contentBottom));
 }
 
-static void nativeAppendPage(JNIEnv* env, jobject thiz, jint documentPtr, jint pagePtr) {
-    SkCanvas* page = reinterpret_cast<SkCanvas*>(pagePtr);
-    SkPDFDocument* document = reinterpret_cast<SkPDFDocument*>(documentPtr);
-    SkPDFDevice* device = static_cast<SkPDFDevice*>(page->getDevice());
-    document->appendPage(device);
+static void nativeFinishPage(JNIEnv* env, jobject thiz, jint documentPtr) {
+    PdfDocument* document = reinterpret_cast<PdfDocument*>(documentPtr);
+    document->finishPage();
 }
 
-static void nativeWriteTo(JNIEnv* env, jobject clazz, jint documentPtr,
-        jobject out, jbyteArray chunk) {
+static void nativeWriteTo(JNIEnv* env, jobject thiz, jint documentPtr, jobject out,
+        jbyteArray chunk) {
+    PdfDocument* document = reinterpret_cast<PdfDocument*>(documentPtr);
     SkWStream* skWStream = CreateJavaOutputStreamAdaptor(env, out, chunk);
-    SkPDFDocument* document = reinterpret_cast<SkPDFDocument*>(documentPtr);
-    document->emitPDF(skWStream);
+    document->write(skWStream);
     delete skWStream;
 }
 
+static void nativeClose(JNIEnv* env, jobject thiz, jint documentPtr) {
+    PdfDocument* document = reinterpret_cast<PdfDocument*>(documentPtr);
+    document->close();
+}
+
 static JNINativeMethod gPdfDocument_Methods[] = {
     {"nativeCreateDocument", "()I", (void*) nativeCreateDocument},
-    {"nativeFinalize", "(I)V", (void*) nativeFinalize},
-    {"nativeCreatePage", "(IIIIII)I",
-            (void*) nativeCreatePage},
-    {"nativeAppendPage", "(II)V", (void*) nativeAppendPage},
-    {"nativeWriteTo", "(ILjava/io/OutputStream;[B)V", (void*) nativeWriteTo}
+    {"nativeStartPage", "(IIIIIII)I", (void*) nativeStartPage},
+    {"nativeFinishPage", "(I)V", (void*) nativeFinishPage},
+    {"nativeWriteTo", "(ILjava/io/OutputStream;[B)V", (void*) nativeWriteTo},
+    {"nativeClose", "(I)V", (void*) nativeClose}
 };
 
 int register_android_graphics_pdf_PdfDocument(JNIEnv* env) {
diff --git a/core/jni/com_android_internal_os_ZygoteInit.cpp b/core/jni/com_android_internal_os_ZygoteInit.cpp
index 44452f0..2233ee3 100644
--- a/core/jni/com_android_internal_os_ZygoteInit.cpp
+++ b/core/jni/com_android_internal_os_ZygoteInit.cpp
@@ -159,29 +159,6 @@
     }
 }
 
-static jlong com_android_internal_os_ZygoteInit_capgetPermitted (JNIEnv *env,
-    jobject clazz, jint pid)
-{
-    struct __user_cap_header_struct capheader;
-    struct __user_cap_data_struct capdata;
-    int err;
-
-    memset (&capheader, 0, sizeof(capheader));
-    memset (&capdata, 0, sizeof(capdata));
-
-    capheader.version = _LINUX_CAPABILITY_VERSION;
-    capheader.pid = pid;
-
-    err = capget (&capheader, &capdata);
-
-    if (err < 0) {
-        jniThrowIOException(env, errno);
-        return 0;
-    }
-
-    return (jlong) capdata.permitted;
-}
-
 static jint com_android_internal_os_ZygoteInit_selectReadable (
         JNIEnv *env, jobject clazz, jobjectArray fds)
 {
@@ -274,8 +251,6 @@
             (void *) com_android_internal_os_ZygoteInit_reopenStdio},
     { "setCloseOnExec", "(Ljava/io/FileDescriptor;Z)V",
         (void *)  com_android_internal_os_ZygoteInit_setCloseOnExec},
-    { "capgetPermitted", "(I)J",
-        (void *) com_android_internal_os_ZygoteInit_capgetPermitted },
     { "selectReadable", "([Ljava/io/FileDescriptor;)I",
         (void *) com_android_internal_os_ZygoteInit_selectReadable },
     { "createFileDescriptor", "(I)Ljava/io/FileDescriptor;",
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index f0fc9e3..8f15471 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1992,6 +1992,14 @@
         android:description="@string/permdesc_bindWallpaper"
         android:protectionLevel="signature|system" />
 
+    <!-- Must be required by a {@link com.android.media.remotedisplay.RemoteDisplayProvider},
+         to ensure that only the system can bind to it.
+         @hide -->
+    <permission android:name="android.permission.BIND_REMOTE_DISPLAY"
+        android:label="@string/permlab_bindRemoteDisplay"
+        android:description="@string/permdesc_bindRemoteDisplay"
+        android:protectionLevel="signature" />
+
     <!-- Must be required by device administration receiver, to ensure that only the
          system can interact with it. -->
     <permission android:name="android.permission.BIND_DEVICE_ADMIN"
diff --git a/core/res/res/drawable-hdpi/toast_frame.9.png b/core/res/res/drawable-hdpi/toast_frame.9.png
index ca65994..a804a8a 100644
--- a/core/res/res/drawable-hdpi/toast_frame.9.png
+++ b/core/res/res/drawable-hdpi/toast_frame.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/toast_frame_holo.9.png b/core/res/res/drawable-hdpi/toast_frame_holo.9.png
deleted file mode 100644
index a804a8a..0000000
--- a/core/res/res/drawable-hdpi/toast_frame_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldpi/toast_frame.9.png b/core/res/res/drawable-ldpi/toast_frame.9.png
index 3b344ff..e64dc75 100644
--- a/core/res/res/drawable-ldpi/toast_frame.9.png
+++ b/core/res/res/drawable-ldpi/toast_frame.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/toast_frame.9.png b/core/res/res/drawable-mdpi/toast_frame.9.png
index 9e93fe7..778e4e6 100644
--- a/core/res/res/drawable-mdpi/toast_frame.9.png
+++ b/core/res/res/drawable-mdpi/toast_frame.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/toast_frame_holo.9.png b/core/res/res/drawable-mdpi/toast_frame_holo.9.png
deleted file mode 100644
index 778e4e6..0000000
--- a/core/res/res/drawable-mdpi/toast_frame_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/toast_frame.9.png b/core/res/res/drawable-xhdpi/toast_frame.9.png
index 1f63420..77e69c7 100644
--- a/core/res/res/drawable-xhdpi/toast_frame.9.png
+++ b/core/res/res/drawable-xhdpi/toast_frame.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/toast_frame_holo.9.png b/core/res/res/drawable-xhdpi/toast_frame_holo.9.png
deleted file mode 100644
index 77e69c7..0000000
--- a/core/res/res/drawable-xhdpi/toast_frame_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/toast_frame.9.png b/core/res/res/drawable-xxhdpi/toast_frame.9.png
index 882b9c6..edecb63 100644
--- a/core/res/res/drawable-xxhdpi/toast_frame.9.png
+++ b/core/res/res/drawable-xxhdpi/toast_frame.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/toast_frame_holo.9.png b/core/res/res/drawable-xxhdpi/toast_frame_holo.9.png
deleted file mode 100644
index edecb63..0000000
--- a/core/res/res/drawable-xxhdpi/toast_frame_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/layout/immersive_mode_cling.xml b/core/res/res/layout/immersive_mode_cling.xml
index f97225e..c0cd93d 100644
--- a/core/res/res/layout/immersive_mode_cling.xml
+++ b/core/res/res/layout/immersive_mode_cling.xml
@@ -37,8 +37,8 @@
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:background="@drawable/cling_bg"
-            android:paddingLeft="14dp"
-            android:paddingRight="14dp"
+            android:paddingStart="14dp"
+            android:paddingEnd="14dp"
             android:paddingTop="24dp"
             android:paddingBottom="24dp">
             <TextView
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index bfca8cd..ea7158a 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -1121,7 +1121,7 @@
     <string name="loading" msgid="7933681260296021180">"Indlæser…"</string>
     <string name="capital_on" msgid="1544682755514494298">"TIL"</string>
     <string name="capital_off" msgid="6815870386972805832">"FRA"</string>
-    <string name="whichApplication" msgid="4533185947064773386">"Fuldfør handling ved hjælp af"</string>
+    <string name="whichApplication" msgid="4533185947064773386">"Brug"</string>
     <string name="whichHomeApplication" msgid="4616420172727326782">"Vælg en startsideapp"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"Brug som standard til denne handling."</string>
     <string name="clearDefaultHintMsg" msgid="3252584689512077257">"Ryd standard i Systemindstillinger &gt; Apps &gt; Downloadet."</string>
diff --git a/core/res/res/values/arrays.xml b/core/res/res/values/arrays.xml
index ef30b98..91af50a 100644
--- a/core/res/res/values/arrays.xml
+++ b/core/res/res/values/arrays.xml
@@ -22,7 +22,7 @@
     <!-- Do not translate. These are all of the drawable resources that should be preloaded by
          the zygote process before it starts forking application processes. -->
     <array name="preloaded_drawables">
-       <item>@drawable/toast_frame_holo</item>
+       <item>@drawable/toast_frame</item>
        <item>@drawable/btn_check_on_pressed_holo_light</item>
        <item>@drawable/btn_check_on_pressed_holo_dark</item>
        <item>@drawable/btn_check_on_holo_light</item>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index a554407..d219ec1 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1052,6 +1052,12 @@
         interface of a wallpaper. Should never be needed for normal apps.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permlab_bindRemoteDisplay">bind to a remote display</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_bindRemoteDisplay">Allows the holder to bind to the top-level
+        interface of a remote display. Should never be needed for normal apps.</string>
+
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_bindRemoteViews">bind to a widget service</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_bindRemoteViews">Allows the holder to bind to the top-level
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index cb706ec..0361df1 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -1068,7 +1068,7 @@
         <item name="presentationTheme">@android:style/Theme.Holo.Dialog.Presentation</item>
 
         <!-- Toast attributes -->
-        <item name="toastFrameBackground">@android:drawable/toast_frame_holo</item>
+        <item name="toastFrameBackground">@android:drawable/toast_frame</item>
 
         <!-- Panel attributes -->
         <item name="panelBackground">@android:drawable/menu_hardkey_panel_holo_dark</item>
@@ -1397,7 +1397,7 @@
         <item name="presentationTheme">@android:style/Theme.Holo.Light.Dialog.Presentation</item>
 
         <!-- Toast attributes -->
-        <item name="toastFrameBackground">@android:drawable/toast_frame_holo</item>
+        <item name="toastFrameBackground">@android:drawable/toast_frame</item>
 
         <!-- Panel attributes -->
         <item name="panelBackground">@android:drawable/menu_hardkey_panel_holo_light</item>
diff --git a/core/res/res/xml/power_profile.xml b/core/res/res/xml/power_profile.xml
index 7af3b9c..3215e17 100644
--- a/core/res/res/xml/power_profile.xml
+++ b/core/res/res/xml/power_profile.xml
@@ -58,4 +58,12 @@
   </array>
   <!-- This is the battery capacity in mAh (measured at nominal voltage) -->
   <item name="battery.capacity">1000</item>
+
+  <array name="wifi.batchedscan"> <!-- mA -->
+      <value>.0002</value> <!-- 1-8/hr -->
+      <value>.002</value>  <!-- 9-64/hr -->
+      <value>.02</value>   <!-- 65-512/hr -->
+      <value>.2</value>    <!-- 513-4,096/hr -->
+      <value>2</value>    <!-- 4097-/hr -->
+  </array>
 </device>
diff --git a/core/tests/bandwidthtests/src/com/android/bandwidthtest/BandwidthTest.java b/core/tests/bandwidthtests/src/com/android/bandwidthtest/BandwidthTest.java
index 76b702e..4a58f88 100644
--- a/core/tests/bandwidthtests/src/com/android/bandwidthtest/BandwidthTest.java
+++ b/core/tests/bandwidthtests/src/com/android/bandwidthtest/BandwidthTest.java
@@ -36,8 +36,6 @@
 import com.android.bandwidthtest.util.ConnectionUtil;
 
 import java.io.File;
-import java.util.HashMap;
-import java.util.Map;
 
 /**
  * Test that downloads files from a test server and reports the bandwidth metrics collected.
@@ -131,8 +129,8 @@
         results.putString("device_id", mDeviceId);
         results.putString("timestamp", ts);
         results.putInt("size", FILE_SIZE);
-        AddStatsToResults(PROF_LABEL, prof_stats, results);
-        AddStatsToResults(PROC_LABEL, proc_stats, results);
+        addStatsToResults(PROF_LABEL, prof_stats, results, mUid);
+        addStatsToResults(PROC_LABEL, proc_stats, results, mUid);
         getInstrumentation().sendStatus(INSTRUMENTATION_IN_PROGRESS, results);
 
         // Clean up.
@@ -185,8 +183,8 @@
         results.putString("device_id", mDeviceId);
         results.putString("timestamp", ts);
         results.putInt("size", FILE_SIZE);
-        AddStatsToResults(PROF_LABEL, prof_stats, results);
-        AddStatsToResults(PROC_LABEL, proc_stats, results);
+        addStatsToResults(PROF_LABEL, prof_stats, results, mUid);
+        addStatsToResults(PROC_LABEL, proc_stats, results, mUid);
         getInstrumentation().sendStatus(INSTRUMENTATION_IN_PROGRESS, results);
 
         // Clean up.
@@ -242,8 +240,9 @@
         results.putString("device_id", mDeviceId);
         results.putString("timestamp", ts);
         results.putInt("size", FILE_SIZE);
-        AddStatsToResults(PROF_LABEL, prof_stats, results);
-        AddStatsToResults(PROC_LABEL, proc_stats, results);
+        addStatsToResults(PROF_LABEL, prof_stats, results, mUid);
+        // remember to use download manager uid for proc stats
+        addStatsToResults(PROC_LABEL, proc_stats, results, downloadManagerUid);
         getInstrumentation().sendStatus(INSTRUMENTATION_IN_PROGRESS, results);
 
         // Clean up.
@@ -302,46 +301,35 @@
      * @param label to attach to this given stats.
      * @param stats {@link NetworkStats} to add.
      * @param results {@link Bundle} to be added to.
+     * @param uid for which to report the results.
      */
-    public void AddStatsToResults(String label, NetworkStats stats, Bundle results){
+    public void addStatsToResults(String label, NetworkStats stats, Bundle results, int uid){
         if (results == null || results.isEmpty()) {
             Log.e(LOG_TAG, "Empty bundle provided.");
             return;
         }
-        // Merge stats across all sets.
-        Map<Integer, Entry> totalStats = new HashMap<Integer, Entry>();
+        Entry totalStats = null;
         for (int i = 0; i < stats.size(); ++i) {
             Entry statsEntry = stats.getValues(i, null);
             // We are only interested in the all inclusive stats.
             if (statsEntry.tag != 0) {
                 continue;
             }
-            Entry mapEntry = null;
-            if (totalStats.containsKey(statsEntry.uid)) {
-                mapEntry = totalStats.get(statsEntry.uid);
-                switch (statsEntry.set) {
-                    case NetworkStats.SET_ALL:
-                        mapEntry.rxBytes = statsEntry.rxBytes;
-                        mapEntry.txBytes = statsEntry.txBytes;
-                        break;
-                    case NetworkStats.SET_DEFAULT:
-                    case NetworkStats.SET_FOREGROUND:
-                        mapEntry.rxBytes += statsEntry.rxBytes;
-                        mapEntry.txBytes += statsEntry.txBytes;
-                        break;
-                    default:
-                        Log.w(LOG_TAG, "Invalid state found in NetworkStats.");
-                }
+            // skip stats for other uids
+            if (statsEntry.uid != uid) {
+                continue;
+            }
+            if (totalStats == null || statsEntry.set == NetworkStats.SET_ALL) {
+                totalStats = statsEntry;
             } else {
-                totalStats.put(statsEntry.uid, statsEntry);
+                totalStats.rxBytes += statsEntry.rxBytes;
+                totalStats.txBytes += statsEntry.txBytes;
             }
         }
-        // Ouput merged stats to bundle.
-        for (Entry entry : totalStats.values()) {
-            results.putInt(label + "uid", entry.uid);
-            results.putLong(label + "tx", entry.txBytes);
-            results.putLong(label + "rx", entry.rxBytes);
-        }
+        // Output merged stats to bundle.
+        results.putInt(label + "uid", totalStats.uid);
+        results.putLong(label + "tx", totalStats.txBytes);
+        results.putLong(label + "rx", totalStats.rxBytes);
     }
 
     /**
diff --git a/data/sounds/AudioPackage10.mk b/data/sounds/AudioPackage10.mk
index 783e1f8..ae4bc88 100644
--- a/data/sounds/AudioPackage10.mk
+++ b/data/sounds/AudioPackage10.mk
@@ -17,19 +17,19 @@
         $(LOCAL_PATH)/alarms/ogg/Osmium.ogg:system/media/audio/alarms/Osmium.ogg \
         $(LOCAL_PATH)/alarms/ogg/Platinum.ogg:system/media/audio/alarms/Platinum.ogg \
 	$(LOCAL_PATH)/effects/ogg/Effect_Tick_48k.ogg:system/media/audio/ui/Effect_Tick.ogg \
-	$(LOCAL_PATH)/effects/ogg/KeypressStandard_120_48k.ogg:system/media/audio/ui/KeypressStandard.ogg \
-	$(LOCAL_PATH)/effects/ogg/KeypressSpacebar_120_48k.ogg:system/media/audio/ui/KeypressSpacebar.ogg \
-	$(LOCAL_PATH)/effects/ogg/KeypressDelete_120_48k.ogg:system/media/audio/ui/KeypressDelete.ogg \
-	$(LOCAL_PATH)/effects/ogg/KeypressInvalid_120_48k.ogg:system/media/audio/ui/KeypressInvalid.ogg \
-	$(LOCAL_PATH)/effects/ogg/KeypressReturn_120_48k.ogg:system/media/audio/ui/KeypressReturn.ogg \
+	$(LOCAL_PATH)/effects/ogg/KeypressStandard_48k.ogg:system/media/audio/ui/KeypressStandard.ogg \
+	$(LOCAL_PATH)/effects/ogg/KeypressSpacebar_48k.ogg:system/media/audio/ui/KeypressSpacebar.ogg \
+	$(LOCAL_PATH)/effects/ogg/KeypressDelete_48k.ogg:system/media/audio/ui/KeypressDelete.ogg \
+	$(LOCAL_PATH)/effects/ogg/KeypressInvalid_48k.ogg:system/media/audio/ui/KeypressInvalid.ogg \
+	$(LOCAL_PATH)/effects/ogg/KeypressReturn_48k.ogg:system/media/audio/ui/KeypressReturn.ogg \
 	$(LOCAL_PATH)/effects/ogg/VideoRecord_48k.ogg:system/media/audio/ui/VideoRecord.ogg \
 	$(LOCAL_PATH)/effects/ogg/camera_click_48k.ogg:system/media/audio/ui/camera_click.ogg \
 	$(LOCAL_PATH)/effects/ogg/camera_focus.ogg:system/media/audio/ui/camera_focus.ogg \
 	$(LOCAL_PATH)/effects/ogg/LowBattery.ogg:system/media/audio/ui/LowBattery.ogg \
 	$(LOCAL_PATH)/effects/ogg/Dock.ogg:system/media/audio/ui/Dock.ogg \
 	$(LOCAL_PATH)/effects/ogg/Undock.ogg:system/media/audio/ui/Undock.ogg \
-	$(LOCAL_PATH)/effects/ogg/Lock.ogg:system/media/audio/ui/Lock.ogg \
-	$(LOCAL_PATH)/effects/ogg/Unlock.ogg:system/media/audio/ui/Unlock.ogg \
+	$(LOCAL_PATH)/effects/ogg/Lock_48k.ogg:system/media/audio/ui/Lock.ogg \
+	$(LOCAL_PATH)/effects/ogg/Unlock_48k.ogg:system/media/audio/ui/Unlock.ogg \
 	$(LOCAL_PATH)/effects/ogg/WirelessChargingStarted.ogg:system/media/audio/ui/WirelessChargingStarted.ogg \
 	$(LOCAL_PATH)/notifications/ogg/Adara.ogg:system/media/audio/notifications/Adara.ogg \
 	$(LOCAL_PATH)/notifications/ogg/Alya.ogg:system/media/audio/notifications/Alya.ogg \
diff --git a/docs/html/about/versions/android-4.4.jd b/docs/html/about/versions/android-4.4.jd
index df9d701..42f257c 100644
--- a/docs/html/about/versions/android-4.4.jd
+++ b/docs/html/about/versions/android-4.4.jd
@@ -474,7 +474,7 @@
 
 <p>To provide batching, the {@link android.hardware.SensorManager} class adds two new versions of the {@link android.hardware.SensorManager#registerListener(SensorEventListener, Sensor, int, int) registerListener()} method that allow you to specify the "maximum report latency." This new parameter specifies the maximum delay that your {@link android.hardware.SensorEventListener} will tolerate for delivery of new sensor events. For example, if you specify a batch latency of one minute, the system will deliver the recent set of batched events at an interval no longer than one minute by making consecutive calls to your {@link android.hardware.SensorEventListener#onSensorChanged onSensorChanged()} method&mdash;once for each event that was batched. The sensor events will never be delayed longer than your maximum report latency value, but may arrive sooner if other apps have requested a shorter latency for the same sensor.</p>
 
-<p>However, be aware that the sensor will deliver your app the batched events based on your report latency <strong>only while the CPU is awake</strong>. Although a hardware sensor that supports batching will continue to collect sensor events while the CPU is asleep, it will not wake the CPU to deliver your app the batched events. When the sensor eventually runs out of its memory for events, it will begin dropping the oldest events in order to save the newest events. You can avoid losing events by waking the device before the sensor fills its memory then call {@link android.hardware.SensorManager#flush flush()} to capture the latest batch of events. To estimate when the memory will be full and should be flushed, call {@link android.hardware.Sensor#getFifoReservedEventCount()} to get the maximum number of sensor events it can save, and divide that number by the rate at which your app desires each event. Use that calculation to set wake alarms with {@link android.app.AlarmManager} that invoke your {@link android.app.Service} (which implements the {@link android.hardware.SensorEventListener}) to flush the sensor.</p>
+<p>However, be aware that the sensor will deliver your app the batched events based on your report latency <strong>only while the CPU is awake</strong>. Although a hardware sensor that supports batching will continue to collect sensor events while the CPU is asleep, it will not wake the CPU to deliver your app the batched events. When the sensor eventually runs out of its memory for events, it will begin dropping the oldest events in order to save the newest events. You can avoid losing events by waking the device before the sensor fills its memory then call {@link android.hardware.SensorManager#flush flush()} to capture the latest batch of events. To estimate when the memory will be full and should be flushed, call {@link android.hardware.Sensor#getFifoMaxEventCount()} to get the maximum number of sensor events it can save, and divide that number by the rate at which your app desires each event. Use that calculation to set wake alarms with {@link android.app.AlarmManager} that invoke your {@link android.app.Service} (which implements the {@link android.hardware.SensorEventListener}) to flush the sensor.</p>
 
 
 <p class="note"><strong>Note:</strong> Not all devices support batching sensor events because it requires support by the hardware sensor. However, beginning with Android 4.4, you should always use the new {@link android.hardware.SensorManager#registerListener(SensorEventListener, Sensor, int, int) registerListener()} methods, because if the device does not support batching, then the system gracefully ignores the batch latency argument and delivers sensor events in real time.</p>
diff --git a/docs/html/about/versions/kitkat.jd b/docs/html/about/versions/kitkat.jd
index 92ebf65..4c80d4e 100644
--- a/docs/html/about/versions/kitkat.jd
+++ b/docs/html/about/versions/kitkat.jd
@@ -992,7 +992,7 @@
   <img src="{@docRoot}images/kk-pseudolocale-rtl.png" alt="" width="260" style=
   "margin-bottom:0;">
   <p class="img-caption" style="padding-top:1.5em;line-height:1.25em;">
-    Pseudo-locales make it easier to test your app's localization.
+    The <strong>Force RTL layout</strong> option makes it easier to test your app's localization.
   </p>
 </div>
 
@@ -1003,18 +1003,18 @@
   files by using a new attribute.
 </p>
 
-<h4 id="44-pseudolocale-rtl">RTL pseudo-locale</h4>
+<h4 id="44-pseudolocale-rtl">Force RTL Layout</h4>
 
 <p>
-  To make it easier to test and debug your layouts, Android includes an RTL
-  pseudo-locale as a new developer option.
+  To make it easier to test and debug your layouts, Android includes a new
+  developer option to force RTL layout direction in all apps.
 </p>
 
 <p>
-  The RTL pseudo-locale switches the device to RTL layout for all locales and
+  The Force RTL layout option switches the device to RTL layout for all locales and
   displays text in your current language. This can help you find layout issues
   across your app, without having to display the app in an RTL language. You
-  can access the RTL pseudo-localed as in <strong>Settings &gt; Developer
+  can access the option in <strong>Settings &gt; Developer
   options &gt; Force RTL layout direction</strong>.
 </p>
 
diff --git a/docs/html/distribute/googleplay/edu/guidelines.jd b/docs/html/distribute/googleplay/edu/guidelines.jd
index c1d3065..7b656b4 100644
--- a/docs/html/distribute/googleplay/edu/guidelines.jd
+++ b/docs/html/distribute/googleplay/edu/guidelines.jd
@@ -28,8 +28,8 @@
 intuitive user experience on Android tablets.</p>
 
 <p>In addition, ensure that your app complies with the terms of a <a
-href="https://play.google.com/about/developer-distribution-agreement-addendum.
-html" target="_policies">Google Play for Education Addendum</a>, as well as
+href="https://play.google.com/about/developer-distribution-agreement-addendum.html"
+target="_policies">Google Play for Education Addendum</a>, as well as
 the standard  <a
 href="http://play.google.com/about/developer-content-policy.html"
 target="_policies">Google Play Developer Program Policies</a> and <a
diff --git a/docs/html/distribute/googleplay/publish/localizing.jd b/docs/html/distribute/googleplay/publish/localizing.jd
index 29b27c8..7788ce1 100644
--- a/docs/html/distribute/googleplay/publish/localizing.jd
+++ b/docs/html/distribute/googleplay/publish/localizing.jd
@@ -293,7 +293,7 @@
 <tr>
 <td><p>Related resources:</p>
 <ul style="margin-top:-.5em;">
-<li><strong><a href="{@docRoot}topics/resources/string-resource.html">String Resources</a></strong> &mdash; Developer guide explaining how to use string resources in your UI.</li>
+<li><strong><a href="{@docRoot}guide/topics/resources/string-resource.html">String Resources</a></strong> &mdash; Developer guide explaining how to use string resources in your UI.</li>
 <li><strong><a href="{@docRoot}design/style/writing.html">Writing Style</a></strong> &mdash; Android Design guidelines for voice and style in your UI.</li>
 <li><strong><a class="external-link" href="http://en.wikipedia.org/wiki/XLIFF">XML Localisation Interchange File Format (XLIFF)</a></strong> &mdash; Background information on XLIFF.</li>
 </ul>
diff --git a/docs/html/distribute/googleplay/publish/preparing.jd b/docs/html/distribute/googleplay/publish/preparing.jd
index 5593f4f..b9dd0e0 100644
--- a/docs/html/distribute/googleplay/publish/preparing.jd
+++ b/docs/html/distribute/googleplay/publish/preparing.jd
@@ -671,7 +671,7 @@
 <li><strong><a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=113477&topic=2364761&ctx=topic">Supporting your users
 </a></strong> &mdash; Help Center document describing options for supporting users.</li>
 <li><strong><a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=1153479">In-app Billing</a></strong> &mdash; Help Center document describing how to correctly set up In-app Billing.</li>
-<li><strong><a href="https://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=138001">Issuing Refunds</a></strong> &mdash;  -- Help Center document describing how to issue refunds.</li>
+<li><strong><a href="https://support.google.com/payments/answer/2741495?rd=1">Issuing Refunds</a></strong> &mdash;  -- Help Center document describing how to issue refunds.</li>
 </ul>
 </td>
 </tr>
diff --git a/docs/html/distribute/googleplay/spotlight/index.jd b/docs/html/distribute/googleplay/spotlight/index.jd
index c599628..b501f20 100644
--- a/docs/html/distribute/googleplay/spotlight/index.jd
+++ b/docs/html/distribute/googleplay/spotlight/index.jd
@@ -55,7 +55,7 @@
           <div style="width:700px;">
           <p style="margin-top:26px;
                     margin-bottom:12px;">
-          Bangalore-based developers <a href="//play-next-dogfood.corp.google.com/store/apps/details?id=in.redbus.android">redBus.in</a> are bringing the sophistication and convenience of air-travel booking to bus transit. Hear how Android is helping them deliver a superior travel experience to millions of daily bus riders in India.</p>
+          Bangalore-based developers <a href="//play.google.com/store/apps/details?id=in.redbus.android">redBus.in</a> are bringing the sophistication and convenience of air-travel booking to bus transit. Hear how Android is helping them deliver a superior travel experience to millions of daily bus riders in India.</p>
            </div>
            <iframe style="float:left;
              margin-right:24px;
diff --git a/docs/html/google/gcm/adv.jd b/docs/html/google/gcm/adv.jd
index 1360624..567b12c 100644
--- a/docs/html/google/gcm/adv.jd
+++ b/docs/html/google/gcm/adv.jd
@@ -22,7 +22,12 @@
   </ol>
 </li>
 <li><a href="#retry">Automatic Retry Using Exponential Back-Off</a></li>
-<li><a href="#unreg">How Unregistration Works</a></li>
+<li><a href="#unreg">Unregistration</a>
+  <ol>
+    <li><a href="#unreg-why">Why you should rarely unregister</a></li>
+    <li><a href="#unreg-how">How unregistration works</a></li>
+  </ol>
+</li>
 <li><a href="#collapsible">Send-to-Sync vs. Messages with Payload</a>
   <ol>
     <li><a href="#s2s">Send-to-sync messages</a></li>
@@ -31,7 +36,8 @@
     </ol>
 </li>
 <li><a href="#ttl">Setting an Expiration Date for a Message</a> </li>
-<li><a href="#throttling"></a><a href="#multi-senders">Receiving Messages from Multiple Senders</a></li>
+<li><a href="#throttling"></a><a href="#multi-senders">Receiving Messages from
+Multiple Senders</a></li>
 </ol>
 
 </div>
@@ -42,17 +48,56 @@
 
 
 <h2 id="msg-lifetime">Lifetime of a Message</h2>
-<p>When a 3rd-party server posts a message to GCM and receives a message ID back, it does not mean that the message was already delivered to the device. Rather, it means that it was accepted for delivery. What happens to the message after it is accepted depends on many factors.</p>
-<p>In the best-case scenario, if the device is connected to GCM, the screen is on, and there are no throttling restrictions (see <a href="#throttling">Throttling</a>), the message will be delivered right away.</p>
+<p>When a 3rd-party server posts a message to GCM and receives a message ID back,
+it does not mean that the message was already delivered to the device. Rather, it
+means that it was accepted for delivery. What happens to the message after it is
+accepted depends on many factors.</p>
+
+<p>In the best-case scenario, if the device is connected to GCM, the screen is on,
+and there are no throttling restrictions (see <a href="#throttling">Throttling</a>),
+the message will be delivered right away.</p>
+
 <p>If the device is connected but idle, the message will still be
-delivered right away unless the <code>delay_while_idle</code> flag is set to true. Otherwise, it will be stored in the GCM servers until the device is awake. And that's where the <code>collapse_key</code> flag plays a role: if there is already a message with the same collapse key (and registration ID) stored and waiting for delivery, the old message will be discarded and the new message will take its place (that is, the old message will be collapsed by the new one). However, if the collapse key is not set, both the new and old messages are stored for future delivery.</p>
+delivered right away unless the <code>delay_while_idle</code> flag is set to true.
+Otherwise, it will be stored in the GCM servers until the device is awake. And
+that's where the <code>collapse_key</code> flag plays a role: if there is already
+a message with the same collapse key (and registration ID) stored and waiting for
+delivery, the old message will be discarded and the new message will take its place
+(that is, the old message will be collapsed by the new one). However, if the collapse
+key is not set, both the new and old messages are stored for future delivery.
+Collapsible messages are also called <a href="#s2s">send-to-sync messages</a>.</p>
 
-<p class="note"><strong>Note:</strong> There is a limit on how many messages can be stored without collapsing. That limit is currently 100. If the limit is reached, all stored messages are discarded. Then when the device is back online, it receives a special message indicating that the limit was reached. The application can then handle the situation properly, typically by requesting a full sync.</p>
+<p class="note"><strong>Note:</strong> There is a limit on how many messages can
+be stored without collapsing. That limit is currently 100. If the limit is reached,
+all stored messages are discarded. Then when the device is back online, it receives
+a special message indicating that the limit was reached. The application can then
+handle the situation properly, typically by requesting a full sync.
+<br><br>
+Likewise, there is a limit on how many <code>collapse_key</code>s you can have for
+a particular device. GCM allows a maximum of 4 different collapse keys to be used
+by the GCM server per device
+any given time. In other words, the GCM server can simultaneously store 4 different
+send-to-sync messages, each with a different collapse key. If you exceed this number
+GCM will only keep 4 collapse keys, with no guarantees about which ones they will be.
+See <a href="#s2s">Send-to-sync messages</a> for more information.
+</p>
 
-<p>If the device is not connected to GCM, the message will be stored until a connection is established (again respecting the collapse key rules). When a connection is established, GCM will deliver all pending messages to the device, regardless of the <code>delay_while_idle</code> flag. If the device never gets connected again (for instance, if it was factory reset), the message will eventually time out and be discarded from GCM storage. The default timeout is 4 weeks, unless the <code>time_to_live</code> flag is set.</p>
+<p>If the device is not connected to GCM, the message will be stored until a
+connection is established (again respecting the collapse key rules). When a connection
+is established, GCM will deliver all pending messages to the device, regardless of
+the <code>delay_while_idle</code> flag. If the device never gets connected again
+(for instance, if it was factory reset), the message will eventually time out and
+be discarded from GCM storage. The default timeout is 4 weeks, unless the
+<code>time_to_live</code> flag is set.</p>
 
-<p>Finally, when GCM attempts to deliver a message to the device and the application was uninstalled, GCM will discard that message right away and invalidate the registration ID. Future attempts to send a message to that device will get a <code>NotRegistered</code> error. See <a href="#unreg">How Unregistration Works</a> for more information.</p>
-<p>Although is not possible to track the status of each individual message, the Google APIs Console stats are broken down by messages sent to device, messages collapsed, and messages waiting for delivery.</p>
+<p>Finally, when GCM attempts to deliver a message to the device and the
+application was uninstalled, GCM will discard that message right away and
+invalidate the registration ID. Future attempts to send a message to that device
+will get a <code>NotRegistered</code> error. See <a href="#unreg">
+How Unregistration Works</a> for more information.</p>
+<p>Although is not possible to track the status of each individual message, the
+Google APIs Console stats are broken down by messages sent to device, messages
+collapsed, and messages waiting for delivery.</p>
 
 <h2 id="throttling">Throttling</h2>
 <p>To prevent abuse (such as sending a flood of messages to a device) and
@@ -74,107 +119,112 @@
 efficiency reasons.</p>
 
 <h2 id="reg-state">Keeping the Registration State in Sync</h2>
-<p>Whenever the application receives a <code>com.google.android.c2dm.intent.REGISTRATION</code> intent with a <code>registration_id</code> extra, it should save the ID for future use, pass it to the 3rd-party server to complete the registration, and keep track of whether the server completed the registration. If the server fails to complete the registration, it should try again or unregister from GCM.</p>
+<p>Whenever the application registers as described in
+<a href="{@docRoot}google/gcm/client.html">Implementing GCM Client</a>,
+it should save the registration ID for future use, pass it to the
+3rd-party server to complete the registration, and keep track of
+whether the server completed the registration. If the server fails
+to complete the registration, it should try again or unregister from GCM.</p>
+
 <p>There are also two other scenarios that require special care:</p>
 <ul>
   <li>Application update</li>
   <li>Backup and restore
   </li>
 </ul>
-<p>When an application is updated, it should invalidate its existing registration ID, as it is not guaranteed to work with the new version.  Because there is no lifecycle method called when the application is updated, the best way to achieve this validation is by storing the current application version when a registration ID is stored. Then when the application is started, compare the stored value with the current application version. If they do not match, invalidate the stored data and start the registration process again.</p>
+<p>When an application is updated, it should invalidate its existing registration
+ID, as it is not guaranteed to work with the new version.  Because there is no
+lifecycle method called when the application is updated, the best way to achieve
+this validation is by storing the current application version when a registration
+ID is stored. Then when the application is started, compare the stored value with
+the current application version. If they do not match, invalidate the stored data
+and start the registration process again.</p>
 
-<p>Similarly, you should not save the registration ID when an application is backed up. This is because the registration ID could become invalid by the time the application is restored, which would put the application in an invalid state  (that is, the application thinks it is registered, but the server and GCM do not store that registration ID anymore&mdash;thus the application will not get more messages).</p>
+<p>Similarly, you should not save the registration ID when an application is
+backed up. This is because the registration ID could become invalid by the time
+the application is restored, which would put the application in an invalid state
+(that is, the application thinks it is registered, but the server and GCM do not
+store that registration ID anymore&mdash;thus the application will not get more
+messages).</p>
 <h3 id="canonical">Canonical IDs</h3>
-<p>On the server side, as long as the application is behaving well, everything should work normally. However, if a bug in the application triggers multiple registrations for the same device, it can be hard to reconcile state and you might end up with duplicate messages.</p>
-<p>GCM provides a facility called &quot;canonical registration IDs&quot; to easily recover from these situations. A canonical registration ID is defined to be the ID of the last registration requested by your application. This is the ID that the server should use when sending messages to the device.</p>
-<p>If later on you try to send a message using a different registration ID, GCM will process the request as usual, but it will include the canonical registration ID in the <code>registration_id</code> field of the response. Make sure to replace the registration ID stored in your server with this canonical ID, as eventually the ID you're using will stop working.</p>
+<p>On the server side, as long as the application is behaving well, everything
+should work normally. However, if a bug in the application triggers multiple
+registrations for the same device, it can be hard to reconcile state and you might
+end up with duplicate messages.</p>
+<p>GCM provides a facility called &quot;canonical registration IDs&quot; to easily
+recover from these situations. A canonical registration ID is defined to be the ID
+of the last registration requested by your application. This is the ID that the
+server should use when sending messages to the device.</p>
+<p>If later on you try to send a message using a different registration ID, GCM
+will process the request as usual, but it will include the canonical registration
+ID in the <code>registration_id</code> field of the response. Make sure to replace
+the registration ID stored in your server with this canonical ID, as eventually
+the ID you're using will stop working.</p>
 
 <h2 id="retry">Automatic Retry Using Exponential Back-Off</h2>
 
-<p>When the application receives a <code>com.google.android.c2dm.intent.REGISTRATION</code> intent with the <code>error</code> extra set as <code>SERVICE_NOT_AVAILABLE</code>, it should retry the failed operation (register or unregister).</p>
-<p>In the simplest case, if your application just calls <code>register</code> and GCM is not a fundamental part of the application, the application could simply ignore the error and try to register again the next time it starts. Otherwise, it should retry the previous operation using exponential back-off. In exponential back-off, each time there is a failure, it should wait twice the previous amount of time before trying again. If the register (or unregister) operation was synchronous, it could be retried in a simple loop. However, since it is asynchronous, the best approach is to schedule a pending intent to retry the operation. The following steps describe how to implement this in the <code>MyIntentService</code> example used above:</p>
-<ol>
-  <li> Create a random token to verify the origin of the retry intent:
+<p>When registration or unregistration fails, the app should retry the failed operation.</p>
+<p>In the simplest case, if your application attempts to register and GCM is not a
+fundamental part of the application, the application could simply ignore the error
+and try to register again the next time it starts. Otherwise, it should retry the
+previous operation using exponential back-off. In exponential back-off, each time
+there is a failure, it should wait twice the previous amount of time before trying
+again. If the register (or unregister) operation was synchronous, it could be retried
+in a simple loop. However, since it is asynchronous, the best approach is to schedule
+a {@link android.app.PendingIntent} to retry the operation.
 
-<pre class="prettyprint pretty-java">private static final String TOKEN =
-        Long.toBinaryString(new Random().nextLong());
-</pre>
+<h2 id="unreg">Unregistration</h2>
 
-  <li> Change the <code>handleRegistration()</code> method so it creates the pending intent when appropriate:</li>
+<p>This section explains when you should unregister in GCM and what happens
+when you do.</p>
 
-<pre class="prettyprint pretty-java">...
-if (error != null) {
- if ("SERVICE_NOT_AVAILABLE".equals(error)) {
-   long backoffTimeMs = // get back-off time from shared preferences
-   long nextAttempt = SystemClock.elapsedRealtime() + backoffTimeMs;
-   Intent retryIntent = new Intent("com.example.gcm.intent.RETRY");
-   retryIntent.putExtra("token", TOKEN);
-   PendingIntent retryPendingIntent =
-       PendingIntent.getBroadcast(context, 0, retryIntent, 0);
-   AlarmManager am = (AlarmManager)   
-       context.getSystemService(Context.ALARM_SERVICE);
-   am.set(AlarmManager.ELAPSED_REALTIME, nextAttempt, retryPendingIntent);
-   backoffTimeMs *= 2; // Next retry should wait longer.
-   // update back-off time on shared preferences
- } else {
-   // Unrecoverable error, log it
-   Log.i(TAG, "Received error: " + error);
-}
-...</pre>
-<p> The back-off time is stored in a shared preference. This ensures that it is persistent across multiple activity launches. The name of the intent does not matter, as long as the same intent is used in the following steps.</p></li>
+<h3 id="unreg-why">Why you should rarely unregister</h3>
 
-  <li> Change the <code>onHandleIntent()</code> method adding an <code>else if</code> case for the retry intent:</li>
+<p>A registration ID (regID) represents a particular Android application running
+on a particular device. You should only need to unregister in rare cases, such as
+if you want an app to stop receiving messages, or if you suspect that the regID has
+been compromised. In general, though, once an app has a regID, you shouldn't need
+to change it.</p>
 
-<pre class="prettyprint pretty-java">...
-} else if (action.equals("com.example.gcm.intent.RETRY")) {
-    String token = intent.getStringExtra("token");
-    // make sure intent was generated by this class, not by a malicious app
-    if (TOKEN.equals(token)) {
-        String registrationId = // get from shared properties
-        if (registrationId != null) {
-        // last operation was attempt to unregister; send UNREGISTER intent again
-    } else {
-        // last operation was attempt to register; send REGISTER intent again
-    }
-}
-...</pre>
+<p>In particular, you should never unregister your app as a mechanism for
+logout or for switching between users, for the following reasons:</p>
 
-  <li> Create a new instance of <code>MyReceiver</code> in your activity:</li>
+<ul>
+  <li>A regID maps an app to a device. It isn't associated with a particular
+  logged in user. If you unregister and then re-register, GCM may return the same
+  ID or a different ID&mdash;there's no guarantee either way.</li>
 
-<pre class="prettyprint pretty-java">private final MyBroadcastReceiver mRetryReceiver = new MyBroadcastReceiver();
-</pre>
+  <li>Unregistration may take up to 5 minutes to propagate.</li>
+  <li>After unregistration, re-registration may again take up to 5 minutes to
+propagate. During this time messages may be rejected due to the state of being
+unregistered, and after all this, messages may still go to the wrong user.</li>
+</ul>
 
-  <li>In the activity's <code>onCreate()</code> method, register the new instance to receive the <code>com.example.gcm.intent.RETRY</code> intent:
-    <pre class="prettyprint pretty-java">...
-IntentFilter filter = new IntentFilter(&quot;com.example.gcm.intent.RETRY&quot;);
-filter.addCategory(getPackageName());
-registerReceiver(mRetryReceiver, filter);
-...</pre>
 
-<p class="note"><strong>Note:</strong> You must dynamically create a new instance of the broadcast receiver since the one defined by the manifest can only receive intents with the <code>com.google.android.c2dm.permission.SEND</code> permission. The permission <code>com.google.android.c2dm.permission.SEND</code> is a system permission and as such it cannot be granted to a regular application.</p>
+<p>The solution is to manage your own mapping between users, the regID, and
+individual messages:</p>
 
-</li>
+<ul>
+  <li>Your app server should maintain a mapping between the current user
+and the regID. This should include information about which user is supposed to
+receive a particular message.</li>
+  <li>The app running on the device should check to ensure that messages it
+receives match the logged in user.</li>
+</ul>
 
-  <li>In the activity's <code>onDestroy()</code> method, unregister the broadcast receiver:</li>
 
-<pre class="prettyprint pretty-java">unregisterReceiver(mRetryReceiver);</pre>
-</ol>
-<h2 id="unreg">How Unregistration Works</h2>
-<p>There are two ways to unregister a device from GCM: manually and automatically.</p>
-<p>An Android application can manually unregister itself by issuing a <code>com.google.android.c2dm.intent.UNREGISTER</code> intent, which is useful when the application offers a logoff feature (so it can unregister on logoff and register again on logon). See the <a href="gcm.html#unregistering">Architectural Overview</a> for more discussion of this topic. This is the sequence of events when an application unregisters itself:</p>
-<ol>
-  <li> The application issues a <code>com.google.android.c2dm.intent.UNREGISTER</code> intent, passing the package name as an extra.</li>
-  <li>When the GCM server is done with the unregistration, it sends a <code>com.google.android.c2dm.intent.REGISTRATION</code> intent with the <code>unregistered</code> extra set.</li>
-  <li>The application then must contact the 3rd-party server so it can remove the registration ID.</li>
-  <li>The application should also clear its registration ID.
-  </li>
-</ol>
-<p>An application can be automatically unregistered after it is uninstalled from the device. However, this process does not happens right away, as Android does not provide an uninstall callback. What happens in this scenario is as follows:</p>
+<h3 id="unreg-how">How unregistration works</h3>
+
+<p>An application can be automatically unregistered after it is uninstalled from
+the device. However, this process does not happens right away, as Android does not
+provide an uninstall callback. What happens in this scenario is as follows:</p>
 <ol>
   <li>The end user uninstalls the application.</li>
   <li>The 3rd-party server sends a message to GCM server.</li>
   <li>The GCM server sends the message to the device.</li>
-  <li>The GCM client receives the message and queries Package Manager about whether there are broadcast receivers configured to receive it, which returns <code>false</code>. 
+  <li>The GCM client receives the message and queries Package Manager about
+whether there are broadcast receivers configured to receive it, which returns
+<code>false</code>.
 </li>
   <li>The GCM client informs the GCM server that the application was uninstalled.</li>
   <li>The GCM server marks the registration ID for deletion.</li>
@@ -184,9 +234,16 @@
   </li>
 </ol>
 
-<p class ="note"><strong>Note:</strong> The GCM client is the Google Cloud Messaging framework present on the device.</p>
+<p class ="note"><strong>Note:</strong> The GCM client is the Google Cloud
+Messaging framework present on the device.</p>
 
-<p>Note that it might take a while for the registration ID be completely removed from GCM. Thus it is possible that messages sent during step 7 above gets a valid message ID as response, even though the message will not be delivered to the device. Eventually, the registration ID will be removed and the server will get a <code>NotRegistered</code> error, without any further action being required from the 3rd-party server (this scenario happens frequently while an application is being developed and tested).</p>
+<p>Note that it might take a while for the registration ID be completely removed
+from GCM. Thus it is possible that messages sent during step 7 above gets a valid
+message ID as response, even though the message will not be delivered to the device.
+Eventually, the registration ID will be removed and the server will get a
+<code>NotRegistered</code> error, without any further action being required from
+the 3rd-party server (this scenario happens frequently while an application is
+being developed and tested).</p>
 
 <h2 id="collapsible">Send-to-Sync  vs. Messages with Payload</h2>
 
@@ -196,17 +253,45 @@
   <li>By default, it is stored by GCM for 4 weeks.</li>
 </ul>
 
-<p>But despite these similarities, messages can behave very differently depending on their particular settings. One major distinction between messages is whether they are collapsed (where each new message replaces the preceding message) or not collapsed (where each individual message is delivered). Every message sent in GCM is either a &quot;send-to-sync&quot; (collapsible) message or a &quot;message with payload&quot; (non-collapsible message). These concepts are described in more detail in the following sections.</p>
+<p>But despite these similarities, messages can behave very differently depending
+on their particular settings. One major distinction between messages is whether
+they are collapsed (where each new message replaces the preceding message) or not
+collapsed (where each individual message is delivered). Every message sent in GCM
+is either a &quot;send-to-sync&quot; (collapsible) message or a &quot;message with
+payload&quot; (non-collapsible message). These concepts are described in more
+detail in the following sections.</p>
 
 <h3 id="s2s"><strong>Send-to-sync messages</strong></h3>
 
-<p>A send-to-sync (collapsible) message is often a &quot;tickle&quot; that tells a mobile application to sync data from the server. For example, suppose you have an email application. When a user receives new email on the server, the server pings the mobile application with a &quot;New mail&quot; message. This tells the application to sync to the server to pick up the new email. The server might send this message multiple times as new mail continues to accumulate, before the application has had a chance to sync. But if the user has received 25 new emails, there's no need to preserve every &quot;New mail&quot; message. One is sufficient. Another example would be a sports application that updates users with the latest score. Only the most recent message is relevant, so it makes sense to have each new message replace the preceding message. </p>
+<p>A send-to-sync (collapsible) message is often a &quot;tickle&quot; that tells
+a mobile application to sync data from the server. For example, suppose you have
+an email application. When a user receives new email on the server, the server
+pings the mobile application with a &quot;New mail&quot; message. This tells the
+application to sync to the server to pick up the new email. The server might send
+this message multiple times as new mail continues to accumulate, before the application
+has had a chance to sync. But if the user has received 25 new emails, there's no
+need to preserve every &quot;New mail&quot; message. One is sufficient. Another
+example would be a sports application that updates users with the latest score.
+Only the most recent message is relevant, so it makes sense to have each new
+message replace the preceding message. </p>
 
-<p>The email and sports applications are cases where you would probably use the GCM <code>collapse_key</code> parameter. A <em>collapse key</em> is an arbitrary string that is used to collapse a group of like messages when the device is offline, so that only the most recent message gets sent to the client. For example, &quot;New mail,&quot; &quot;Updates available,&quot; and so on</p>
-<p>GCM allows a maximum of 4 different collapse keys to be used by the GCM server at any given time. In other words, the GCM server can simultaneously store 4 different send-to-sync messages, each with a different collapse key. If you exceed this number GCM will only keep 4 collapse keys, with no guarantees about which ones they will be.</p>
+<p>The email and sports applications are cases where you would probably use the
+GCM <code>collapse_key</code> parameter. A <em>collapse key</em> is an arbitrary
+string that is used to collapse a group of like messages when the device is offline,
+so that only the most recent message gets sent to the client. For example,
+&quot;New mail,&quot; &quot;Updates available,&quot; and so on</p>
+<p>GCM allows a maximum of 4 different collapse keys to be used by the GCM server
+at any given time. In other words, the GCM server can simultaneously store 4
+different send-to-sync messages per device, each with a different collapse key.
+For example, Device A can have A1, A2, A3, and A4. Device B can have B1, B2, B3,
+and B4, and so on. If you exceed this number GCM will only keep 4 collapse keys, with no
+guarantees about which ones they will be.</p>
 
 <h3 id="payload">Messages with payload</h3>
-<p>Unlike a send-to-sync message, every &quot;message with payload&quot; (non-collapsible message) is delivered. The payload the message contains can be up to 4kb. For example, here is a JSON-formatted message in an IM application in which spectators are discussing a sporting event:</p>
+<p>Unlike a send-to-sync message, every &quot;message with payload&quot;
+(non-collapsible message) is delivered. The payload the message contains can be
+up to 4kb. For example, here is a JSON-formatted message in an IM application in
+which spectators are discussing a sporting event:</p>
 
 <pre class="prettyprint pretty-json">{
   "registration_id" : "APA91bHun4MxP5egoKMwt2KZFBaFUH-1RYqx...",
@@ -217,19 +302,42 @@
   },
 }</pre>
 
-<p>A &quot;message with payload&quot; is not simply a &quot;ping&quot; to the mobile application to contact the server to fetch data. In the aforementioned IM application, for example, you would want to deliver every message, because every message has different content. To specify a non-collapsible message, you simply omit the <code>collapse_key</code> parameter. Thus GCM will send each message individually. Note that the order of delivery is not guaranteed.</p>
-<p>GCM will store up to 100 non-collapsible messages. After that, all messages are discarded from GCM, and a new message is created that tells the client how far behind it is. The message is delivered through a regular <code>com.google.android.c2dm.intent.RECEIVE</code> intent, with the following extras:</p>
+<p>A &quot;message with payload&quot; is not simply a &quot;ping&quot; to the
+mobile application to contact the server to fetch data. In the aforementioned IM
+application, for example, you would want to deliver every message, because every
+message has different content. To specify a non-collapsible message, you simply
+omit the <code>collapse_key</code> parameter. Thus GCM will send each message
+individually. Note that the order of delivery is not guaranteed.</p>
+
+<p>GCM will store up to 100 non-collapsible messages. After that, all messages
+are discarded from GCM, and a new message is created that tells the client how
+far behind it is. The message is delivered through a regular
+<code>com.google.android.c2dm.intent.RECEIVE</code> intent, with the following
+extras:</p>
 <ul>
-  <li> <code>message_type</code>&mdash;The value is always the string &quot;deleted_messages&quot;.</li>
-  <li><code>total_deleted</code>&mdash;The value  is a string with the number of deleted messages.</li>
+  <li> <code>message_type</code>&mdash;The value is always the string
+&quot;deleted_messages&quot;.</li>
+  <li><code>total_deleted</code>&mdash;The value  is a string with the number of
+deleted messages.</li>
 </ul>
-<p>The application should respond by syncing with the server to recover the discarded messages. </p>
+<p>The application should respond by syncing with the server to recover the
+discarded messages. </p>
 
 <h3 id="which">Which should I use?</h3>
-  <p>If your application does not need to use non-collapsible messages, collapsible messages are a better choice from a performance standpoint, because they put less of a burden on the device battery.</p>
+  <p>If your application does not need to use non-collapsible messages, collapsible
+messages are a better choice from a performance standpoint, because they put less
+of a burden on the device battery. However, if you use collapsible messages, remember that
+<strong>GCM only allows a maximum of 4 different collapse keys to be used by the GCM server
+per device at any given time</strong>. You must not exceed this number, or it could cause
+unpredictable consequences.</p>
 
 <h2 dir="ltr" id="ttl">Setting an Expiration Date for a Message</h2>
-<p>The Time to Live (TTL) feature lets  the sender  specify the maximum lifespan of a message using the <code>time_to_live</code> parameter in the send request. The value of this parameter must be a duration from 0 to 2,419,200 seconds, and it corresponds to the maximum period of time for which GCM will store and try to deliver the message. Requests that don't contain this field default to the maximum period of 4 weeks.</p>
+<p>The Time to Live (TTL) feature lets  the sender  specify the maximum lifespan
+of a message using the <code>time_to_live</code> parameter in the send request.
+The value of this parameter must be a duration from 0 to 2,419,200 seconds, and
+it corresponds to the maximum period of time for which GCM will store and try to
+deliver the message. Requests that don't contain this field default to the maximum
+period of 4 weeks.</p>
 <p>Here are some possible uses for this feature:</p>
 <ul>
   <li>Video chat incoming calls</li>
@@ -237,9 +345,29 @@
   <li>Calendar events</li>
 </ul>
 <h3 id="bg">Background </h3>
-<p>GCM will usually deliver messages immediately after they are sent. However, this might not always be possible. For example, the device could be turned off, offline, or otherwise unavailable. In other cases, the sender itself might request that messages not be delivered until the device becomes active by using the <code>delay_while_idle</code> flag. Finally, GCM might intentionally delay messages to prevent an application from consuming excessive resources and negatively impacting battery life.</p>
-<p>When this happens, GCM will store the message and deliver it as soon as it's feasible. While this is fine in most cases, there are some applications for which a late message might as well never be delivered. For example, if the message is an incoming call or video chat notification, it will only be meaningful for a small period of time before the call is terminated. Or if the message is an invitation to an event, it will be useless if received after the event has ended.</p>
-<p>Another advantage of specifying the expiration date for a message is that GCM will never throttle messages with a <code>time_to_live</code> value of 0 seconds. In other words, GCM will guarantee best effort for messages that must be delivered &quot;now or never.&quot; Keep in mind that a <code>time_to_live</code> value of 0 means messages that can't be delivered immediately will be discarded. However, because such messages are never stored, this provides the best latency for sending notifications.</p>
+<p>GCM will usually deliver messages immediately after they are sent. However,
+this might not always be possible. For example, the device could be turned off,
+offline, or otherwise unavailable. In other cases, the sender itself might request
+that messages not be delivered until the device becomes active by using the
+<code>delay_while_idle</code> flag. Finally, GCM might intentionally delay messages
+to prevent an application from consuming excessive resources and negatively
+impacting battery life.</p>
+
+<p>When this happens, GCM will store the message and deliver it as soon as it's
+feasible. While this is fine in most cases, there are some applications for which
+a late message might as well never be delivered. For example, if the message is
+an incoming call or video chat notification, it will only be meaningful for a
+small period of time before the call is terminated. Or if the message is an
+invitation to an event, it will be useless if received after the event has ended.</p>
+
+<p>Another advantage of specifying the expiration date for a message is that GCM
+will never throttle messages with a <code>time_to_live</code> value of 0 seconds.
+In other words, GCM will guarantee best effort for messages that must be delivered
+&quot;now or never.&quot; Keep in mind that a <code>time_to_live</code> value of
+0 means messages that can't be delivered immediately will be discarded. However,
+because such messages are never stored, this provides the best latency for
+sending notifications.</p>
+
 <p>Here is an example of a JSON-formatted request that includes TTL:</p>
 <pre class="prettyprint pretty-json">
 {
@@ -256,9 +384,23 @@
 
 
 <h2 id="multi-senders">Receiving Messages from Multiple Senders</h2>
-<p>GCM allows multiple parties to send messages to the same application. For example, suppose your application is an articles aggregator with multiple contributors, and you want each of them to be able to send a message when they publish a new article. This message might contain a URL so that the application can download the article. Instead of having to centralize all sending activity in one location, GCM gives you the ability to let each of these contributors send its own messages.</p>
-<p>To make this possible, all you need to do is have each sender generate its own project number. Then include those IDs in the sender field, separated by commas, when requesting a registration. Finally, share the registration ID with your partners, and they'll be able to send messages to your application using their own authentication keys.</p>
-<p>This code snippet illustrates this feature. Senders are passed as an intent extra in a comma-separated list:</p>
+
+<p>GCM allows multiple parties to send messages to the same application. For
+example, suppose your application is an articles aggregator with multiple
+contributors, and you want each of them to be able to send a message when they
+publish a new article. This message might contain a URL so that the application
+can download the article. Instead of having to centralize all sending activity in
+one location, GCM gives you the ability to let each of these contributors send
+its own messages.</p>
+
+<p>To make this possible, all you need to do is have each sender generate its own
+project number. Then include those IDs in the sender field, separated by commas,
+when requesting a registration. Finally, share the registration ID with your
+partners, and they'll be able to send messages to your application using their
+own authentication keys.</p>
+<p>This code snippet illustrates this feature. Senders are passed as an intent
+extra in a comma-separated list:</p>
+
 <pre class="prettyprint pretty-java">Intent intent = new Intent(GCMConstants.INTENT_TO_GCM_REGISTRATION);
 intent.setPackage(GSF_PACKAGE);
 intent.putExtra(GCMConstants.EXTRA_APPLICATION_PENDING_INTENT,
@@ -269,4 +411,3 @@
  </pre>
 
 <p>Note that there is limit of 100 multiple senders.</p>
- 
diff --git a/docs/html/google/gcm/ccs.jd b/docs/html/google/gcm/ccs.jd
index 0cadbd2..d2177ca 100644
--- a/docs/html/google/gcm/ccs.jd
+++ b/docs/html/google/gcm/ccs.jd
@@ -1,93 +1,96 @@
-page.title=GCM Cloud Connection Server
+page.title=GCM Cloud Connection Server (XMPP)
 @jd:body
 
 <div id="qv-wrapper">
 <div id="qv">
 
-<h2>Quickview</h2>
-
-<ul>
-<li>Get an introduction to key CCS terms and concepts.</li>
-<li>Learn how to send and receive both upstream and downstream messages in CCS.</li>
-</ul>
-
 
 <h2>In this document</h2>
 
 <ol class="toc">
-  <li><a href="#gcm">CCS vs. GCM HTTP</a> </li>
   <li><a href="#usage">How to Use CCS</a>
-    <ol>
-      <li><a href="#send_msg">Sending Messages</a></li>
-      <li><a href="#format">Message Format</a></li>
-      <li><a href="#msg_examples">Message Examples</a></li>
+    <ol class="toc">
+      <li><a href="#auth">Authentication</a></li>
+      </ol>
+      </li>
+    <li><a href="#format">Message Format</a>
+      <ol class="toc">
+        <li><a href="#request">Request format</a></li>
+        <li><a href="#response">Response format</a></li>
+      </ol>
+      </li>
+  <li><a href="#upstream">Upstream Messages</a> </li>
+  <li><a href="#flow">Flow Control</a> </li>
+  <li><a href="#implement">Implementing an XMPP-based App Server</a>
+    <ol class="toc">
+      <li><a href="#smack">Java sample using the Smack library</a></li>
+      <li><a href="#python">Python sample</a></li>
     </ol>
   </li>
-  <li><a href="#flow">Flow Control</a> </li>
 </ol>
 
 <h2>See Also</h2>
 
 <ol class="toc">
-<li><a href="{@docRoot}google/play-services/gcm/gs.html">Getting Started</a></li>
-<li><a href="https://services.google.com/fb/forms/gcm/" class="external-link" target="_android">CCS and User Notifications Signup Form</a></li>
+<li><a href="{@docRoot}google/gcm/http.html">HTTP</a></li>
+<li><a href="{@docRoot}google/gcm/gs.html">Getting Started</a></li>
+<li><a href="{@docRoot}google/gcm/server.html">Implementing GCM Server</a></li>
+<li><a href="{@docRoot}google/gcm/client.html">Implementing GCM Client</a></li>
+<li><a href="https://services.google.com/fb/forms/gcm/" class="external-link"
+target="_android">CCS and User Notifications Signup Form</a></li>
 </ol>
 
 </div>
 </div>
 
-<p class="note"><strong>Note:</strong> To try out this feature, sign up using <a href="https://services.google.com/fb/forms/gcm/">this form</a>.</p>
+<p class="note"><strong>Note:</strong> To try out this feature, sign up using
+<a href="https://services.google.com/fb/forms/gcm/">this form</a>.</p>
 
-<p>The GCM Cloud Connection Server (CCS) allows third party servers to communicate with Android devices by  establishing a persistent TCP connection with Google servers using the XMPP protocol. This communication is asynchronous and bidirectional.</p>
-<p>You can continue to use the HTTP request mechanism to send messages to GCM servers, side-by-side with CCS which uses XMPP. Some of the benefits of CCS include:</p>
+<p>The GCM Cloud Connection Server (CCS) is a connection server based on XMPP.
+CCS allows 3rd-party app servers (which you're
+responsible for implementing) to communicate
+with Android devices by  establishing a persistent TCP connection with Google
+servers using the XMPP protocol. This communication is asynchronous and bidirectional.</p>
+<p>You can continue to use the HTTP request mechanism to send messages to GCM
+servers, side-by-side with CCS which uses XMPP. Some of the benefits of CCS include:</p>
 <ul>
-  <li>The asynchronous nature of XMPP allows you to send more messages with fewer resources.</li>
-  <li>Communication is bidirectional&mdash;not only can the server send messages to the device, but the device can send messages back to the server.</li>
-<li>You can send messages back using the same connection used for receiving, thereby improving battery life.</li>
+  <li>The asynchronous nature of XMPP allows you to send more messages with fewer
+resources.</li>
+  <li>Communication is bidirectional&mdash;not only can the server send messages
+to the device, but the device can send messages back to the server.</li>
+<li>You can send messages back using the same connection used for receiving,
+thereby improving battery life.</li>
 </ul>
 
-<p>The upstream messaging (device-to-cloud) feature of CCS is part of the Google Play services platform. Upstream messaging is available through the <a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">{@code GoogleCloudMessaging}</a> APIs. To use upstream messaging and the new streamlined registration process, you must <a href="{@docRoot}google/play-services/setup.html">set up</a> the Google Play services SDK.</p>
+<p>The upstream messaging (device-to-cloud) feature of CCS is part of the Google
+Play services platform. Upstream messaging is available through the
+<a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">
+{@code GoogleCloudMessaging}</a>
+APIs. For examples, see
+<a href="#implement">Implementing an XMPP-based App Server</a>.</p>
 
-<p class="note"><strong>Note:</strong> For an example of an XMPP server, see <a href="server.html#xmpp">GCM Server</a>.
+<p class="note"><strong>Note:</strong> See
+<a href="server.html#params">Implementing GCM Server</a> for a list of all the message
+parameters and which connection server(s) supports them.</p>
 
-<h2 id="gcm">CCS vs. GCM HTTP</h2>
-
-<p>CCS messaging differs from GCM HTTP messaging in the following ways:</p>
-<ul>
-  <li>Upstream/Downstream messages
-    <ul>
-      <li>GCM HTTP: Downstream only: cloud-to-device. </li>
-      <li>CCS: Upstream and downstream (device-to-cloud, cloud-to-device). </li>
-    </ul>
-  </li>
-  <li>Asynchronous messaging
-    <ul>
-      <li>GCM HTTP: 3rd-party servers send messages as HTTP POST requests and wait for a response. This mechanism is synchronous and causes the sender to block before sending another message.</li>
-      <li>CCS: 3rd-party servers connect to Google infrastructure using a persistent XMPP connection and send/receive messages to/from all their devices at full line speed. CCS sends acknowledgements or failure notifications (in the form of special ACK and NACK JSON-encoded XMPP messages) asynchronously.</li>
-    </ul>
-  </li>
-
-  <li>JSON
-    <ul>
-      <li>GCM HTTP: JSON messages sent as HTTP POST.</li>
-      <li>CCS: JSON messages encapsulated in XMPP messages.</li>
-    </ul>
-  </li>
-</ul>
-<p>This document describes how to use CCS. For general concepts and information on how to use GCM HTTP, see the <a href="gcm.html">GCM Architectural Overview</a>.</p>
 
 <h2 id="usage">How to Use CCS</h2>
 
-<p>GCM Cloud Connection Server (CCS) is an XMPP endpoint, running on {@code http://gcm.googleapis.com} port 5235.</p>
+<p>GCM Cloud Connection Server (CCS) is an XMPP endpoint, running on
+{@code http://gcm.googleapis.com} port 5235.</p>
 
-<p>CCS requires a Transport Layer Security (TLS) connection. That means the  XMPP client must initiate a TLS connection.
-For example in smack, you would call {@code setSocketFactory(SSLSocketFactory)}, similar to “old style SSL” XMPP connections and https.</p>
+<p>CCS requires a Transport Layer Security (TLS) connection. That means the  XMPP
+client must initiate a TLS connection.
+For example in Java, you would call {@code setSocketFactory(SSLSocketFactory)}.</p>
 
-<p>CCS requires a SASL PLAIN authentication mechanism using {@code &lt;your_GCM_Sender_Id&gt;&#64;gcm.googleapis.com} (GCM sender ID) and the API key as the password, where the sender ID and API key are the same as described in <a href="gs.html">Getting Started</a>.</p>
+<p>CCS requires a SASL PLAIN authentication mechanism using
+{@code &lt;your_GCM_Sender_Id&gt;&#64;gcm.googleapis.com} (GCM sender ID) and the
+API key as the password, where the sender ID and API key are the same as described
+in <a href="gs.html">Getting Started</a>.</p>
 
 <p> You can use most XMPP libraries to interact with CCS.</p>
 
-<h3 id="send_msg">Sending messages</h3>
+<h3 id="auth">Authentication</h3>
 
 <p>The following snippets illustrate how to perform authentication in CCS.</p>
 <h4>Client</h4>
@@ -108,13 +111,13 @@
 <h4>Client</h4>
 <pre>&lt;auth mechanism=&quot;PLAIN&quot;
 xmlns=&quot;urn:ietf:params:xml:ns:xmpp-sasl&quot;&gt;MTI2MjAwMzQ3OTMzQHByb2plY3RzLmdjbS5hb
-mRyb2lkLmNvbQAxMjYyMDAzNDc5FzNAcHJvamVjdHMtZ2EtLmFuZHJvaWQuY29tAEFJe
 mFTeUIzcmNaTmtmbnFLZEZiOW1oekNCaVlwT1JEQTJKV1d0dw==&lt;/auth&gt;
 </pre>
+
 <h4>Server</h4>
 <pre>&lt;success xmlns=&quot;urn:ietf:params:xml:ns:xmpp-sasl&quot;/&gt;</pre>
 
-<h3 id="format">Message Format</h3>
+<h2 id="format">Message Format</h2>
 <p>CCS uses normal XMPP <code>&lt;message&gt;</code> stanzas. The body of the message must be:
 </p>
 <pre>
@@ -123,25 +126,42 @@
 &lt;/gcm&gt;
 </pre>
 
-<p>The JSON payload for server-to-device is similar to what the GCM http endpoint uses, with these exceptions:</p>
+<p>The JSON payload for server-to-device is similar to what the GCM http endpoint
+uses, with these exceptions:</p>
 <ul>
   <li>There is no support for multiple recipients.</li>
   <li>{@code to} is used instead of {@code registration_ids}.</li>
-  <li>CCS adds the field {@code message_id}, which is required. This ID uniquely identifies the message in an XMPP connection. The ACK or NACK from CCS uses the {@code message_id} to identify a message sent from 3rd-party servers to CCS. Therefore, it's important that this {@code message_id} not only be unique, but always present.</li>
+  <li>CCS adds the field {@code message_id}, which is required. This ID uniquely
+identifies the message in an XMPP connection. The ACK or NACK from CCS uses the
+{@code message_id} to identify a message sent from 3rd-party app servers to CCS.
+Therefore, it's important that this {@code message_id} not only be unique, but
+always present.</li>
 
-  <li>For ACK/NACK messages that are special control messages, you also need to include a {@code message_type} field in the JSON message. For example:
+<li>For ACK/NACK messages that are special control messages, you also need to
+include a {@code message_type} field in the JSON message. The value can be either
+'ack' or 'nack'. For example:
 
-<pre>message_type = ('ack' OR 'nack');</pre>
+<pre>message_type = ('ack');</pre>
   </li>
 </ul>
-<p>For each message a device sends to the server, you need to send an ACK message. You never need to send a NACK message. If you don't send an ACK for a message, CCS will just resend it.
+<p>For each device message your app server receives from CCS, it needs to send
+an ACK message.
+It never needs to send a NACK message. If you don't send an ACK for a message,
+CCS will just resend it.
 </p>
-<p>CCS also sends an ACK or NACK for each server-to-device message. If you do not receive either, it means that the TCP connection was closed in the middle of the operation and your server needs to resend the messages.
+<p>CCS also sends an ACK or NACK for each server-to-device message. If you do not
+receive either, it means that the TCP connection was closed in the middle of the
+operation and your server needs to resend the messages. See
+<a href="#flow">Flow Control</a> for details.
 </p>
 
-<h3 id="msg_examples">Message Examples</h3>
+<p class="note"><strong>Note:</strong> See
+<a href="server.html#params">Implementing GCM Server</a> for a list of all the message
+parameters and which connection server(s) supports them.</p>
 
-<p>Here is an XMPP stanza containing the JSON message from a 3rd-party server to CCS:
+<h3 id="request">Request format</h3>
+
+<p>Here is an XMPP stanza containing the JSON message from a 3rd-party app server to CCS:
 
 </p>
 <pre>&lt;message id=&quot;&quot;&gt;
@@ -160,7 +180,15 @@
 &lt;/message&gt;
 </pre>
 
-<p>Here is an XMPP stanza containing the ACK/NACK message from CCS to 3rd-party server:
+<h3 id="response">Response format</h3>
+
+<p>A CCS response can have 3 possible forms. The first one is a regular 'ack'
+message. But when the response contains an error, there are 2
+different forms the message can take, described below.</p>
+
+<h4 id="ack">ACK message</h4>
+
+<p>Here is an XMPP stanza containing the ACK/NACK message from CCS to 3rd-party app server:
 </p>
 <pre>&lt;message id=&quot;&quot;&gt;
   &lt;gcm xmlns=&quot;google:mobile:data&quot;&gt;
@@ -171,24 +199,138 @@
   }
   &lt;/gcm&gt;
 &lt;/message&gt;
+</pre>
 
-&lt;message id=&quot;&quot;&gt;
-  &lt;gcm xmlns=&quot;google:mobile:data&quot;&gt;
+<h4 id="nack">NACK message</h4>
+
+<p>A NACK error is a regular XMPP message in which the {@code message_type} status
+message is &quot;nack&quot;. A NACK message contains:</p>
+<ul>
+<li>Nack error code.</li>
+<li>Nack error description.</li>
+</ul>
+
+<p>Below are some examples.</p>
+
+<p>Bad registration:</p>
+<pre>&lt;message&gt;
+  &lt;data:gcm xmlns:data=&quot;google:mobile:data&quot;&gt;
   {
-      &quot;from&quot;:&quot;REGID&quot;,
-      &quot;message_id&quot;:&quot;m-1366082849205&quot;
-      &quot;error&quot;: ERROR_CODE,
-      &quot;message_type&quot;:&quot;nack&quot;
+    &quot;error&quot;:&quot;BAD_REGISTRATION&quot;,  // error code
+    &quot;message_id&quot;:&quot;msgId1&quot;,
+    &quot;from&quot;:&quot;PA91bHFOtaQGSwupt5l1og&quot;,
+    &quot;message_type&quot;:&quot;nack&quot;
   }
+  &lt;/data:gcm&gt;
+&lt;/message&gt;</pre>
+
+<p>Invalid "time to live":</p>
+
+<pre>&lt;message&gt;
+  &lt;data:gcm xmlns:data=&quot;google:mobile:data&quot;&gt;
+  {
+     &quot;error&quot;:&quot;InvalidJson : INVALID_TTL : Invalid value (-1) for \&quot;time_to_live\&quot;: must be between 0 and \&quot;2419200\&quot;\n&quot;,
+     &quot;message_id&quot;:&quot;msgId1&quot;,
+     &quot;from&quot;:&quot;APA91bHFOtaQGSwupt5l1og&quot;,
+     &quot;message_type&quot;:&quot;nack&quot;
+  }
+  &lt;/data:gcm&gt;
+&lt;/message&gt;</pre>
+
+<p>JSON type error:</p>
+
+<pre>&lt;message&gt;
+  &lt;data:gcm xmlns:data=&quot;google:mobile:data&quot;&gt;
+  {
+     &quot;error&quot;:&quot;InvalidJson : JSON_TYPE_ERROR : Field \&quot;delay_while_idle\&quot; must be a JSON java.lang.Boolean: not-boolean-user-supplied-value\n&quot;,
+     &quot;message_id&quot;:&quot;msgId1&quot;,
+     &quot;from&quot;:&quot;APA91bHFOtaQGSwupt5l1og&quot;,
+     &quot;message_type&quot;:&quot;nack&quot;
+  }
+  &lt;/data:gcm&gt;
+&lt;/message&gt;</pre>
+
+
+<p>The following table lists some of the more common NACK error codes.</p>
+
+<p class="table-caption" id="table1">
+  <strong>Table 1.</strong> NACK error codes.</p>
+
+<table border="1">
+<tr>
+<th>Error Code</th>
+<th>Description</th>
+</tr>
+<tr>
+<td>{@code BAD_REGISTRATION}</td>
+<td>The device has a registration ID, but it's invalid.</td>
+</tr>
+<tr>
+<td>{@code DEVICE_UNREGISTERED}</td>
+<td>The device is not registered.</td>
+</tr>
+<tr>
+<td>{@code INTERNAL_SERVER_ERROR}</td>
+<td>The server encountered an error while trying to process the request.</td>
+</tr>
+<tr>
+<td>{@code SERVICE_UNAVAILABLE}</td>
+<td>The CCS connection server is temporarily unavailable, try again later
+(using exponential backoff, etc.).</td>
+</tr>
+<tr>
+<td>{@code BAD_ACK}</td>
+<td>The ACK message is improperly formed.</td>
+</tr>
+<tr>
+<td>{@code AUTHENTICATION_FAILED}</td>
+<td>This is a 401 error indicating that there was an error authenticating the sender account.</td>
+</tr>
+<tr>
+<td>{@code INVALID_TTL}</td>
+<td>There was an error in the supplied "time to live" value.</td>
+</tr>
+<tr>
+<td>{@code JSON_TYPE_ERROR}</td>
+<td>There was an error in the supplied JSON data type.</td>
+</tr>
+</table>
+
+<h4 id="stanza">Stanza error</h4>
+
+<p>You can also get a stanza error in certain cases.
+A stanza error contains:</p>
+<ul>
+<li>Stanza error code.</li>
+<li>Stanza error description (free text).</li>
+</ul>
+<p>For example:</p>
+
+<pre>&lt;message id=&quot;3&quot; type=&quot;error&quot; to=&quot;123456789@gcm.googleapis.com/ABC&quot;&gt;
+  &lt;gcm xmlns=&quot;google:mobile:data&quot;&gt;
+     {&quot;random&quot;: &quot;text&quot;}
   &lt;/gcm&gt;
+  &lt;error code=&quot;400&quot; type=&quot;modify&quot;&gt;
+    &lt;bad-request xmlns=&quot;urn:ietf:params:xml:ns:xmpp-stanzas&quot;/&gt;
+    &lt;text xmlns=&quot;urn:ietf:params:xml:ns:xmpp-stanzas&quot;&gt;
+      InvalidJson: JSON_PARSING_ERROR : Missing Required Field: message_id\n
+    &lt;/text&gt;
+  &lt;/error&gt;
 &lt;/message&gt;
 </pre>
 
-<h4>Upstream Messages</h4>
 
-<p>Using CCS and the <a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">GoogleCloudMessaging</a> API, you can send messages from a user's device to the cloud.</p>
+<h2 id="upstream">Upstream Messages</h2>
 
-<p>Here is how you send an upstream message using the <a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">GoogleCloudMessaging</a> API. For a complete example, see <a href="gs.html#gs_example">Getting Started</a>:</p>
+<p>Using CCS and the
+<a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">
+{@code GoogleCloudMessaging}</a>
+API, you can send messages from a user's device to the cloud.</p>
+
+<p>Here is how you send an upstream message using the
+<a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">
+{@code GoogleCloudMessaging}</a>
+API. For a complete example, see <a href="client.html">Implementing GCM Client</a>:</p>
 
 <pre>GoogleCloudMessaging gcm = GoogleCloudMessaging.get(context);
 String GCM_SENDER_ID = "Your-Sender-ID";
@@ -198,12 +340,15 @@
 // Bundle data consists of a key-value pair
 data.putString("hello", "world");
 // "time to live" parameter
+// This is optional. It specifies a value in seconds up to 4 weeks.
 int ttl = [0 seconds, 4 weeks]
 
 gcm.send(GCM_SENDER_ID + "&#64;gcm.googleapis.com", id, ttl, data);
 </pre>
 
-<p>This call generates the necessary XMPP stanza for sending the upstream message. The message goes from the app on the device to CCS to the 3rd-party server. The stanza has the following format:</p>
+<p>This call generates the necessary XMPP stanza for sending the upstream message.
+The message goes from the app on the device to CCS to the 3rd-party app server.
+The stanza has the following format:</p>
 
 <pre>&lt;message id=&quot;&quot;&gt;
   &lt;gcm xmlns=&quot;google:mobile:data&quot;&gt;
@@ -219,7 +364,8 @@
   &lt;/gcm&gt;
 &lt;/message&gt;</pre>
 
-<p>Here is the format of the ACK expected by CCS from 3rd-party servers in response to the above message:</p>
+<p>Here is the format of the ACK expected by CCS from 3rd-party app servers in
+response to the above message:</p>
 
 <pre>&lt;message id=&quot;&quot;&gt;
   &lt;gcm xmlns=&quot;google:mobile:data&quot;&gt;
@@ -231,13 +377,478 @@
   &lt;/gcm&gt;
 &lt;/message&gt;</pre>
 
-
 <h2 id="flow">Flow Control</h2>
 
-<p>Every message sent to CCS receives either an ACK or a NACK response. Messages that haven't received one of these responses are considered pending. If the pending message count reaches 1000, the 3rd-party server should stop sending new messages and wait for CCS to acknowledge some of the existing pending messages.</p>
+<p>Every message sent to CCS receives either an ACK or a NACK response. Messages
+that haven't received one of these responses are considered pending. If the pending
+message count reaches 1000, the 3rd-party app server should stop sending new messages
+and wait for CCS to acknowledge some of the existing pending messages as illustrated in
+figure 1:</p>
 
-<p>Conversely, to avoid overloading the 3rd-party server, CCS will stop sending if there are too many unacknowledged messages. Therefore, the 3rd-party server should "ACK" received messages as soon as possible to maintain a constant flow of incoming messages. The aforementioned pending message limit doesn't apply to these ACKs. Even if the pending message count reaches 1000, the 3rd-party server should continue sending ACKs to avoid blocking delivery of new messages.</p>
+<img src="{@docRoot}images/gcm/CCS-ack.png">
 
-<p>ACKs are only valid within the context of one connection. If the connection is closed before a message can be ACKed, the 3rd-party server should wait for CCS to resend the message before ACKing it again.
+<p class="img-caption">
+  <strong>Figure 1.</strong> Message/ack flow.
 </p>
 
+<p>Conversely, to avoid overloading the 3rd-party app server, CCS will stop sending
+if there are too many unacknowledged messages. Therefore, the 3rd-party app server
+should "ACK" upstream messages, received from the client application via CCS, as soon as possible
+to maintain a constant flow of incoming messages. The aforementioned pending message limit doesn't
+apply to these ACKs. Even if the pending message count reaches 1000, the 3rd-party app server
+should continue sending ACKs for messages received from CCS to avoid blocking delivery of new
+upstream messages.</p>
+
+<p>ACKs are only valid within the context of one connection. If the connection is
+closed before a message can be ACKed, the 3rd-party app server should wait for CCS
+to resend the upstream message before ACKing it again. Similarly, all pending messages for which an
+ACK/NACK was not received from CCS before the connection was closed should be sent again.
+</p>
+
+<h2 id="implement">Implementing an XMPP-based App Server</h2>
+
+<p>This section gives examples of implementing an app server that works with CCS.
+Note that a full GCM implementation requires a client-side implementation, in
+addition to the server. For more information, see <a href="client.html">
+Implementing GCM Client</a>.</a>
+
+<h3 id="smack">Java sample using the Smack library</h3>
+
+<p>Here is a sample app server written in Java, using the
+<a href="http://www.igniterealtime.org/projects/smack/">Smack</a> library.</p>
+
+<pre>import org.jivesoftware.smack.ConnectionConfiguration;
+import org.jivesoftware.smack.ConnectionConfiguration.SecurityMode;
+import org.jivesoftware.smack.ConnectionListener;
+import org.jivesoftware.smack.PacketInterceptor;
+import org.jivesoftware.smack.PacketListener;
+import org.jivesoftware.smack.XMPPConnection;
+import org.jivesoftware.smack.XMPPException;
+import org.jivesoftware.smack.filter.PacketTypeFilter;
+import org.jivesoftware.smack.packet.DefaultPacketExtension;
+import org.jivesoftware.smack.packet.Message;
+import org.jivesoftware.smack.packet.Packet;
+import org.jivesoftware.smack.packet.PacketExtension;
+import org.jivesoftware.smack.provider.PacketExtensionProvider;
+import org.jivesoftware.smack.provider.ProviderManager;
+import org.jivesoftware.smack.util.StringUtils;
+import org.json.simple.JSONValue;
+import org.json.simple.parser.ParseException;
+import org.xmlpull.v1.XmlPullParser;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Random;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.net.ssl.SSLSocketFactory;
+/**
+ * Sample Smack implementation of a client for GCM Cloud Connection Server.
+ *
+ * &lt;p&gt;For illustration purposes only.
+ */
+public class SmackCcsClient {
+
+  Logger logger = Logger.getLogger(&quot;SmackCcsClient&quot;);
+
+  public static final String GCM_SERVER = &quot;gcm.googleapis.com&quot;;
+  public static final int GCM_PORT = 5235;
+
+  public static final String GCM_ELEMENT_NAME = &quot;gcm&quot;;
+  public static final String GCM_NAMESPACE = &quot;google:mobile:data&quot;;
+
+  static Random random = new Random();
+  XMPPConnection connection;
+  ConnectionConfiguration config;
+
+  /**
+   * XMPP Packet Extension for GCM Cloud Connection Server.
+   */
+  class GcmPacketExtension extends DefaultPacketExtension {
+    String json;
+
+    public GcmPacketExtension(String json) {
+      super(GCM_ELEMENT_NAME, GCM_NAMESPACE);
+      this.json = json;
+    }
+
+    public String getJson() {
+      return json;
+    }
+
+    &#64;Override
+    public String toXML() {
+      return String.format(&quot;&lt;%s xmlns=\&quot;%s\&quot;&gt;%s&lt;/%s&gt;&quot;, GCM_ELEMENT_NAME,
+          GCM_NAMESPACE, json, GCM_ELEMENT_NAME);
+    }
+
+    &#64;SuppressWarnings(&quot;unused&quot;)
+    public Packet toPacket() {
+      return new Message() {
+        // Must override toXML() because it includes a &lt;body&gt;
+        &#64;Override
+        public String toXML() {
+
+          StringBuilder buf = new StringBuilder();
+          buf.append(&quot;&lt;message&quot;);
+          if (getXmlns() != null) {
+            buf.append(&quot; xmlns=\&quot;&quot;).append(getXmlns()).append(&quot;\&quot;&quot;);
+          }
+          if (getLanguage() != null) {
+            buf.append(&quot; xml:lang=\&quot;&quot;).append(getLanguage()).append(&quot;\&quot;&quot;);
+          }
+          if (getPacketID() != null) {
+            buf.append(&quot; id=\&quot;&quot;).append(getPacketID()).append(&quot;\&quot;&quot;);
+          }
+          if (getTo() != null) {
+            buf.append(&quot; to=\&quot;&quot;).append(StringUtils.escapeForXML(getTo())).append(&quot;\&quot;&quot;);
+          }
+          if (getFrom() != null) {
+            buf.append(&quot; from=\&quot;&quot;).append(StringUtils.escapeForXML(getFrom())).append(&quot;\&quot;&quot;);
+          }
+          buf.append(&quot;&gt;&quot;);
+          buf.append(GcmPacketExtension.this.toXML());
+          buf.append(&quot;&lt;/message&gt;&quot;);
+          return buf.toString();
+        }
+      };
+    }
+  }
+
+  public SmackCcsClient() {
+    // Add GcmPacketExtension
+    ProviderManager.getInstance().addExtensionProvider(GCM_ELEMENT_NAME,
+        GCM_NAMESPACE, new PacketExtensionProvider() {
+
+      &#64;Override
+      public PacketExtension parseExtension(XmlPullParser parser)
+          throws Exception {
+        String json = parser.nextText();
+        GcmPacketExtension packet = new GcmPacketExtension(json);
+        return packet;
+      }
+    });
+  }
+
+  /**
+   * Returns a random message id to uniquely identify a message.
+   *
+   * &lt;p&gt;Note:
+   * This is generated by a pseudo random number generator for illustration purpose,
+   * and is not guaranteed to be unique.
+   *
+   */
+  public String getRandomMessageId() {
+    return &quot;m-&quot; + Long.toString(random.nextLong());
+  }
+
+  /**
+   * Sends a downstream GCM message.
+   */
+  public void send(String jsonRequest) {
+    Packet request = new GcmPacketExtension(jsonRequest).toPacket();
+    connection.sendPacket(request);
+  }
+
+  /**
+   * Handles an upstream data message from a device application.
+   *
+   * &lt;p&gt;This sample echo server sends an echo message back to the device.
+   * Subclasses should override this method to process an upstream message.
+   */
+  public void handleIncomingDataMessage(Map&lt;String, Object&gt; jsonObject) {
+    String from = jsonObject.get(&quot;from&quot;).toString();
+
+    // PackageName of the application that sent this message.
+    String category = jsonObject.get(&quot;category&quot;).toString();
+
+    // Use the packageName as the collapseKey in the echo packet
+    String collapseKey = &quot;echo:CollapseKey&quot;;
+    &#64;SuppressWarnings(&quot;unchecked&quot;)
+    Map&lt;String, String&gt; payload = (Map&lt;String, String&gt;) jsonObject.get(&quot;data&quot;);
+    payload.put(&quot;ECHO&quot;, &quot;Application: &quot; + category);
+
+    // Send an ECHO response back
+    String echo = createJsonMessage(from, getRandomMessageId(), payload, collapseKey, null, false);
+    send(echo);
+  }
+
+  /**
+   * Handles an ACK.
+   *
+   * &lt;p&gt;By default, it only logs a {@code INFO} message, but subclasses could override it to
+   * properly handle ACKS.
+   */
+  public void handleAckReceipt(Map&lt;String, Object&gt; jsonObject) {
+    String messageId = jsonObject.get(&quot;message_id&quot;).toString();
+    String from = jsonObject.get(&quot;from&quot;).toString();
+    logger.log(Level.INFO, &quot;handleAckReceipt() from: &quot; + from + &quot;, messageId: &quot; + messageId);
+  }
+
+  /**
+   * Handles a NACK.
+   *
+   * &lt;p&gt;By default, it only logs a {@code INFO} message, but subclasses could override it to
+   * properly handle NACKS.
+   */
+  public void handleNackReceipt(Map&lt;String, Object&gt; jsonObject) {
+    String messageId = jsonObject.get(&quot;message_id&quot;).toString();
+    String from = jsonObject.get(&quot;from&quot;).toString();
+    logger.log(Level.INFO, &quot;handleNackReceipt() from: &quot; + from + &quot;, messageId: &quot; + messageId);
+  }
+
+  /**
+   * Creates a JSON encoded GCM message.
+   *
+   * &#64;param to RegistrationId of the target device (Required).
+   * &#64;param messageId Unique messageId for which CCS will send an &quot;ack/nack&quot; (Required).
+   * &#64;param payload Message content intended for the application. (Optional).
+   * &#64;param collapseKey GCM collapse_key parameter (Optional).
+   * &#64;param timeToLive GCM time_to_live parameter (Optional).
+   * &#64;param delayWhileIdle GCM delay_while_idle parameter (Optional).
+   * &#64;return JSON encoded GCM message.
+   */
+  public static String createJsonMessage(String to, String messageId, Map&lt;String, String&gt; payload,
+      String collapseKey, Long timeToLive, Boolean delayWhileIdle) {
+    Map&lt;String, Object&gt; message = new HashMap&lt;String, Object&gt;();
+    message.put(&quot;to&quot;, to);
+    if (collapseKey != null) {
+      message.put(&quot;collapse_key&quot;, collapseKey);
+    }
+    if (timeToLive != null) {
+      message.put(&quot;time_to_live&quot;, timeToLive);
+    }
+    if (delayWhileIdle != null &amp;&amp; delayWhileIdle) {
+      message.put(&quot;delay_while_idle&quot;, true);
+    }
+    message.put(&quot;message_id&quot;, messageId);
+    message.put(&quot;data&quot;, payload);
+    return JSONValue.toJSONString(message);
+  }
+
+  /**
+   * Creates a JSON encoded ACK message for an upstream message received from an application.
+   *
+   * &#64;param to RegistrationId of the device who sent the upstream message.
+   * &#64;param messageId messageId of the upstream message to be acknowledged to CCS.
+   * &#64;return JSON encoded ack.
+   */
+  public static String createJsonAck(String to, String messageId) {
+    Map&lt;String, Object&gt; message = new HashMap&lt;String, Object&gt;();
+    message.put(&quot;message_type&quot;, &quot;ack&quot;);
+    message.put(&quot;to&quot;, to);
+    message.put(&quot;message_id&quot;, messageId);
+    return JSONValue.toJSONString(message);
+  }
+
+  /**
+   * Connects to GCM Cloud Connection Server using the supplied credentials.
+   *
+   * &#64;param username GCM_SENDER_ID&#64;gcm.googleapis.com
+   * &#64;param password API Key
+   * &#64;throws XMPPException
+   */
+  public void connect(String username, String password) throws XMPPException {
+    config = new ConnectionConfiguration(GCM_SERVER, GCM_PORT);
+    config.setSecurityMode(SecurityMode.enabled);
+    config.setReconnectionAllowed(true);
+    config.setRosterLoadedAtLogin(false);
+    config.setSendPresence(false);
+    config.setSocketFactory(SSLSocketFactory.getDefault());
+
+    // NOTE: Set to true to launch a window with information about packets sent and received
+    config.setDebuggerEnabled(true);
+
+    // -Dsmack.debugEnabled=true
+    XMPPConnection.DEBUG_ENABLED = true;
+
+    connection = new XMPPConnection(config);
+    connection.connect();
+
+    connection.addConnectionListener(new ConnectionListener() {
+
+      &#64;Override
+      public void reconnectionSuccessful() {
+        logger.info(&quot;Reconnecting..&quot;);
+      }
+
+      &#64;Override
+      public void reconnectionFailed(Exception e) {
+        logger.log(Level.INFO, &quot;Reconnection failed.. &quot;, e);
+      }
+
+      &#64;Override
+      public void reconnectingIn(int seconds) {
+        logger.log(Level.INFO, &quot;Reconnecting in %d secs&quot;, seconds);
+      }
+
+      &#64;Override
+      public void connectionClosedOnError(Exception e) {
+        logger.log(Level.INFO, &quot;Connection closed on error.&quot;);
+      }
+
+      &#64;Override
+      public void connectionClosed() {
+        logger.info(&quot;Connection closed.&quot;);
+      }
+    });
+
+    // Handle incoming packets
+    connection.addPacketListener(new PacketListener() {
+
+      &#64;Override
+      public void processPacket(Packet packet) {
+        logger.log(Level.INFO, &quot;Received: &quot; + packet.toXML());
+        Message incomingMessage = (Message) packet;
+        GcmPacketExtension gcmPacket =
+            (GcmPacketExtension) incomingMessage.getExtension(GCM_NAMESPACE);
+        String json = gcmPacket.getJson();
+        try {
+          &#64;SuppressWarnings(&quot;unchecked&quot;)
+          Map&lt;String, Object&gt; jsonObject =
+              (Map&lt;String, Object&gt;) JSONValue.parseWithException(json);
+
+          // present for &quot;ack&quot;/&quot;nack&quot;, null otherwise
+          Object messageType = jsonObject.get(&quot;message_type&quot;);
+
+          if (messageType == null) {
+            // Normal upstream data message
+            handleIncomingDataMessage(jsonObject);
+
+            // Send ACK to CCS
+            String messageId = jsonObject.get(&quot;message_id&quot;).toString();
+            String from = jsonObject.get(&quot;from&quot;).toString();
+            String ack = createJsonAck(from, messageId);
+            send(ack);
+          } else if (&quot;ack&quot;.equals(messageType.toString())) {
+            // Process Ack
+            handleAckReceipt(jsonObject);
+          } else if (&quot;nack&quot;.equals(messageType.toString())) {
+            // Process Nack
+            handleNackReceipt(jsonObject);
+          } else {
+            logger.log(Level.WARNING, &quot;Unrecognized message type (%s)&quot;,
+                messageType.toString());
+          }
+        } catch (ParseException e) {
+          logger.log(Level.SEVERE, &quot;Error parsing JSON &quot; + json, e);
+        } catch (Exception e) {
+          logger.log(Level.SEVERE, &quot;Couldn't send echo.&quot;, e);
+        }
+      }
+    }, new PacketTypeFilter(Message.class));
+
+
+    // Log all outgoing packets
+    connection.addPacketInterceptor(new PacketInterceptor() {
+      &#64;Override
+      public void interceptPacket(Packet packet) {
+        logger.log(Level.INFO, &quot;Sent: {0}&quot;,  packet.toXML());
+      }
+    }, new PacketTypeFilter(Message.class));
+
+    connection.login(username, password);
+  }
+
+  public static void main(String [] args) {
+    final String userName = &quot;Your GCM Sender Id&quot; + &quot;&#64;gcm.googleapis.com&quot;;
+    final String password = &quot;API Key&quot;;
+
+    SmackCcsClient ccsClient = new SmackCcsClient();
+
+    try {
+      ccsClient.connect(userName, password);
+    } catch (XMPPException e) {
+      e.printStackTrace();
+    }
+
+    // Send a sample hello downstream message to a device.
+    String toRegId = &quot;RegistrationIdOfTheTargetDevice&quot;;
+    String messageId = ccsClient.getRandomMessageId();
+    Map&lt;String, String&gt; payload = new HashMap&lt;String, String&gt;();
+    payload.put(&quot;Hello&quot;, &quot;World&quot;);
+    payload.put(&quot;CCS&quot;, &quot;Dummy Message&quot;);
+    payload.put(&quot;EmbeddedMessageId&quot;, messageId);
+    String collapseKey = &quot;sample&quot;;
+    Long timeToLive = 10000L;
+    Boolean delayWhileIdle = true;
+    ccsClient.send(createJsonMessage(toRegId, messageId, payload, collapseKey,
+        timeToLive, delayWhileIdle));
+  }
+}</pre>
+<h3 id="python">Python sample</h3>
+
+<p>Here is an example of a CCS app server written in Python. This sample echo
+server sends an initial message, and for every upstream message received, it sends
+a dummy response back to the application that sent the upstream message. This
+example illustrates how to connect, send, and receive GCM messages using XMPP. It
+shouldn't be used as-is on a production deployment.</p>
+
+<pre>
+#!/usr/bin/python
+import sys, json, xmpp, random, string
+
+SERVER = 'gcm.googleapis.com'
+PORT = 5235
+USERNAME = "Your GCM Sender Id"
+PASSWORD = "API Key"
+REGISTRATION_ID = "Registration Id of the target device"
+
+unacked_messages_quota = 1000
+send_queue = []
+
+# Return a random alphanumerical id
+def random_id():
+  rid = ''
+  for x in range(8): rid += random.choice(string.ascii_letters + string.digits)
+  return rid
+
+def message_callback(session, message):
+  global unacked_messages_quota
+  gcm = message.getTags('gcm')
+  if gcm:
+    gcm_json = gcm[0].getData()
+    msg = json.loads(gcm_json)
+    if not msg.has_key('message_type'):
+      # Acknowledge the incoming message immediately.
+      send({'to': msg['from'],
+            'message_type': 'ack',
+            'message_id': msg['message_id']})
+      # Queue a response back to the server.
+      if msg.has_key('from'):
+        # Send a dummy echo response back to the app that sent the upstream message.
+        send_queue.append({'to': msg['from'],
+                           'message_id': random_id(),
+                           'data': {'pong': 1}})
+    elif msg['message_type'] == 'ack' or msg['message_type'] == 'nack':
+      unacked_messages_quota += 1
+
+def send(json_dict):
+  template = (&quot;&lt;message&gt;&lt;gcm xmlns='google:mobile:data'&gt;{1}&lt;/gcm&gt;&lt;/message&gt;&quot;)
+  client.send(xmpp.protocol.Message(
+      node=template.format(client.Bind.bound[0], json.dumps(json_dict))))
+
+def flush_queued_messages():
+  global unacked_messages_quota
+  while len(send_queue) and unacked_messages_quota &gt; 0:
+    send(send_queue.pop(0))
+    unacked_messages_quota -= 1
+
+client = xmpp.Client('gcm.googleapis.com', debug=['socket'])
+client.connect(server=(SERVER,PORT), secure=1, use_srv=False)
+auth = client.auth(USERNAME, PASSWORD)
+if not auth:
+  print 'Authentication failed!'
+  sys.exit(1)
+
+client.RegisterHandler('message', message_callback)
+
+send_queue.append({'to': REGISTRATION_ID,
+                   'message_id': 'reg_id',
+                   'data': {'message_destination': 'RegId',
+                            'message_id': random_id()}})
+
+while True:
+  client.Process(1)
+  flush_queued_messages()</pre>
diff --git a/docs/html/google/gcm/client.jd b/docs/html/google/gcm/client.jd
index 7604932..df357a2 100644
--- a/docs/html/google/gcm/client.jd
+++ b/docs/html/google/gcm/client.jd
@@ -1,24 +1,663 @@
-page.title=GCM Client
+page.title=Implementing GCM Client
 page.tags="cloud","push","messaging"
 @jd:body
 
 <div id="qv-wrapper">
 <div id="qv">
 
+
+<h2>In this document</h2>
+
+<ol class="toc">
+<li><a href="#play-services">Set Up Google Play Services</a></li>
+<li><a href="#manifest">Edit Your Application's Manifest</a></li>
+<li><a href="#app">Write Your Application</a>
+  <ol class="toc">
+    <li><a href="#sample-play">Check for Google Play Services APK</a></li>
+    <li><a href="#sample-register">Register for GCM</a></li>
+    <li><a href="#sample-send">Send a message</a></li>
+    <li><a href="#sample-receive">Receive a message</a></li>
+  </ol>
+  <li><a href="#run">Running the Sample</a></li>
+  <li><a href="#stats">Viewing Statistics</a></li>
+</li>
+
+</ol>
+
 <h2>See Also</h2>
 
 <ol class="toc">
 <li><a href="gs.html">Getting Started</a></li>
-<li><a href="server.html">GCM Server</a></li>
+<li><a href="server.html">Implementing GCM Server</a></li>
 </ol>
 
 </div>
 </div>
 
-<p>A GCM client is a GCM-enabled app that runs on an Android device. To write your client code, we recommend that you use the new <a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">{@code GoogleCloudMessaging}</a> APIs. The client helper library that was offered in previous versions of GCM still works, but it has been superseded by the more efficient <a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">{@code GoogleCloudMessaging}</a> APIs.</p>
+<p>A GCM client is a GCM-enabled app that runs on an Android device. To write your
+client code, we recommend that you use the
+<a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">
+{@code GoogleCloudMessaging}</a> APIs.
+The client helper library that was offered in previous versions of GCM still works,
+but it has been superseded by the more efficient
+<a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">
+{@code GoogleCloudMessaging}</a> APIs.</p>
 
-<p>A full GCM implementation requires both a client implementation and a server-side implementation. For a step-by-step guide to creating a complete sample implementation that includes both client and server, see <a href="gs.html">Getting Started</a>. </p>
+<p>A full GCM implementation requires both a client implementation and a server
+implementation. For more
+information about implementing the server side, see <a href="server.html">
+Implementing GCM Server</a>.</p>
 
-<p>
+<p>The following sections walk you through the steps involved in writing a GCM
+client-side application. Your client app can be arbitrarily complex, but at bare
+minimum, a GCM client app must include code to register (and thereby get a
+registration ID), and a broadcast receiver to receive messages sent by GCM.
+</p>
+
+<h2 id="play-services">Step 1: Set Up Google Play Services</h2>
+
+<p>To write your client application, use the
+<a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">
+{@code GoogleCloudMessaging}</a> API.
+To use this API, you must set up your project to use the Google Play services SDK,
+as described in <a href="/google/play-services/setup.html">Setup Google Play
+Services SDK</a>.</p>
+
+<p class="note"><strong>Caution:</strong> When you add the Play Services library to
+your project, be sure to add it <em>with resources</em>, as described in
+<a href="{@docRoot}google/play-services/setup.html#Setup">
+Setup Google Play Services SDK</a>. The key point is that you must
+<em>reference</em> the library&mdash;simply adding a {@code .jar} file to
+your Eclipse project will not work. You must follow the directions
+for referencing a library, or your app won't be able to access
+the library's resources, and it won't run properly.
+If you're using Android Studio, this is the string to add to the
+{@code dependency} section of your application's {@code build.gradle} file:</p>
+
+<pre>dependencies {
+   compile: "com.google.android.gms:play-services:3.1.+"
+}
+</pre>
+
+
+<h2 id="manifest">Step 2: Edit Your Application's Manifest</h2>
+
+<p>Add the following to your application's manifest:</p>
+<ul>
+  <li>The <code>com.google.android.c2dm.permission.RECEIVE</code> permission so
+the Android application can register and receive messages.</li>
+  <li>The <code>android.permission.INTERNET</code> permission so the Android
+application can send the registration ID to the 3rd party server.</li>
+  <li>The <code>android.permission.GET_ACCOUNTS</code> permission as GCM requires
+a Google account (necessary only if if the device is running a version lower than
+Android 4.0.4)</li>
+  <li>The <code>android.permission.WAKE_LOCK</code> permission so the application
+can keep the processor from sleeping when a message is received. Optional&mdash;use
+only if the app wants to keep the device from sleeping.</li>
+  <li>An <code>applicationPackage + &quot;.permission.C2D_MESSAGE&quot;</code>
+permission to prevent other Android applications from registering and receiving
+the Android application's messages. The permission name must exactly match this
+pattern&mdash;otherwise the Android application will not receive the messages.</li>
+   <li>A receiver for <code>com.google.android.c2dm.intent.RECEIVE</code>, with
+the category set
+as <code>applicationPackage</code>. The receiver should require the
+<code>com.google.android.c2dm.SEND</code> permission, so that only the GCM
+Framework can send a message to it. If your app uses an {@link android.app.IntentService}
+(not required, but a common pattern), this receiver should be an instance of
+{@link android.support.v4.content.WakefulBroadcastReceiver}.
+A {@link android.support.v4.content.WakefulBroadcastReceiver} takes care of
+creating and managing a
+<a href="{@docRoot}reference/android/os/PowerManager.html#PARTIAL_WAKE_LOCK">
+partial wake lock</a> for your app.</li>
+
+<li>A {@link android.app.Service} (typically an {@link android.app.IntentService})
+to which the {@link android.support.v4.content.WakefulBroadcastReceiver} passes off
+the work of handling the GCM message, while ensuring that the device does not
+go back to sleep in the process. Including an {@link android.app.IntentService} is
+optional&mdash;you could choose to process your messages in a regular
+{@link android.content.BroadcastReceiver} instead, but realistically, most apps will
+use a {@link android.app.IntentService}.
+</li>
+  <li>If the GCM feature is critical to the Android application's function, be sure to
+set <code>android:minSdkVersion=&quot;8&quot;</code> or higher in the manifest. This
+ensures that the Android application cannot be installed in an environment in which it
+could not run properly. </li>
+</ul>
+
+<p>Here are excerpts from a sample manifest that supports GCM:</p>
+
+<pre class="prettyprint pretty-xml">
+&lt;manifest package="com.example.gcm" ...&gt;
+
+    &lt;uses-sdk android:minSdkVersion="8" android:targetSdkVersion="17"/&gt;
+    &lt;uses-permission android:name="android.permission.INTERNET" /&gt;
+    &lt;uses-permission android:name="android.permission.GET_ACCOUNTS" /&gt;
+    &lt;uses-permission android:name="android.permission.WAKE_LOCK" /&gt;
+    &lt;uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" /&gt;
+
+    &lt;permission android:name="com.example.gcm.permission.C2D_MESSAGE"
+        android:protectionLevel="signature" /&gt;
+    &lt;uses-permission android:name="com.example.gcm.permission.C2D_MESSAGE" /&gt;
+
+    &lt;application ...&gt;
+        &lt;receiver
+            android:name=".GcmBroadcastReceiver"
+            android:permission="com.google.android.c2dm.permission.SEND" &gt;
+            &lt;intent-filter&gt;
+                &lt;action android:name="com.google.android.c2dm.intent.RECEIVE" /&gt;
+                &lt;category android:name="com.example.gcm" /&gt;
+            &lt;/intent-filter&gt;
+        &lt;/receiver&gt;
+        &lt;service android:name=".GcmIntentService" /&gt;
+    &lt;/application&gt;
+
+&lt;/manifest&gt;
+</pre>
+
+<h2 id="app"> Step 3: Write Your Application</h2>
+
+<p>Finally, write your application. This section features a sample client
+application that illustrates how to use the
+<a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">
+{@code GoogleCloudMessaging}</a> APIs. The sample consists of a main activity
+({@code DemoActivity}), a {@link android.support.v4.content.WakefulBroadcastReceiver}
+({@code GcmBroadcastReceiver}), and an {@link android.app.IntentService}
+({@code GcmIntentService}). You can find the complete source code for this sample at the
+<a href="http://code.google.com/p/gcm">open source site</a>.</p>
+
+<p>Note the following:</p>
+
+<ul>
+  <li>Among other things, the sample illustrates registration and upstream
+(device-to-cloud) messaging. Upstream messaging only applies to apps that are running against a
+<a href="ccs.html">CCS</a> (XMPP) server; HTTP-based servers don't support upstream messaging.</li>
+  <li>The <a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">
+  {@code GoogleCloudMessaging}</a>
+registration APIs replace the old registration process, which was based on the
+now-obsolete client helper library. While the old registration process still works,
+we encourage you to use the newer
+<a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">
+{@code GoogleCloudMessaging}</a>
+registration APIs, regardless of your underlying server.</li>
+</ul>
+
+<h3 id="sample-play">Check for Google Play Services APK</h3>
+
+<p>As described in <a href="{@docRoot}google/play-services/setup.html">
+Setup Google Play Services SDK</a>, apps that rely on the Play Services SDK
+should always check the device for a compatible Google Play services APK before
+accessing Google Play services features. In the sample app this check is done in
+two places: in the main activity's {@code onCreate()} method, and in its
+{@code onResume()} method. The check in {@code onCreate()} ensures that the app
+can't be used without a successful check. The check in {@code onResume()} ensures
+that if the user returns to the running app through some other means, such as
+through the back button, the check is still performed. If the
+device doesn't have a compatible Google Play services APK, your app can call
+{@code GooglePlayServicesUtil.getErrorDialog()} to allow users to download the
+APK from the Google Play Store or enable it in the device's system settings.
+For example:</p>
+
+<pre>private final static int PLAY_SERVICES_RESOLUTION_REQUEST = 9000;
+...
+&#64;Override
+public void onCreate(Bundle savedInstanceState) {
+    super.onCreate(savedInstanceState);
+
+    setContentView(R.layout.main);
+    mDisplay = (TextView) findViewById(R.id.display);
+
+    context = getApplicationContext();
+
+    // Check device for Play Services APK.
+    if (checkPlayServices()) {
+        // If this check succeeds, proceed with normal processing.
+        // Otherwise, prompt user to get valid Play Services APK.
+        ...
+    }
+}
+
+// You need to do the Play Services APK check here too.
+&#64;Override
+protected void onResume() {
+    super.onResume();
+    checkPlayServices();
+}
+
+/**
+ * Check the device to make sure it has the Google Play Services APK. If
+ * it doesn't, display a dialog that allows users to download the APK from
+ * the Google Play Store or enable it in the device's system settings.
+ */
+private boolean checkPlayServices() {
+    int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
+    if (resultCode != ConnectionResult.SUCCESS) {
+        if (GooglePlayServicesUtil.isUserRecoverableError(resultCode)) {
+            GooglePlayServicesUtil.getErrorDialog(resultCode, this,
+                    PLAY_SERVICES_RESOLUTION_REQUEST).show();
+        } else {
+            Log.i(TAG, "This device is not supported.");
+            finish();
+        }
+        return false;
+    }
+    return true;
+}</pre>
+
+<h3 id="sample-register">Register for GCM</h3>
+<p>An Android application needs to register with GCM servers before it can receive
+messages. When an app registers, it receives a registration ID, which it can then
+store for future use. In the following snippet the {@code onCreate()} method in the sample app's
+main activity checks to see if the app is already registered with GCM and with
+the server:</p>
+
+<pre>/**
+ * Main UI for the demo app.
+ */
+public class DemoActivity extends Activity {
+
+    public static final String EXTRA_MESSAGE = "message";
+    public static final String PROPERTY_REG_ID = "registration_id";
+    private static final String PROPERTY_APP_VERSION = "appVersion";
+    private final static int PLAY_SERVICES_RESOLUTION_REQUEST = 9000;
+
+    /**
+     * Substitute you own sender ID here. This is the project number you got
+     * from the API Console, as described in "Getting Started."
+     */
+    String SENDER_ID = "Your-Sender-ID";
+
+    /**
+     * Tag used on log messages.
+     */
+    static final String TAG = "GCMDemo";
+
+    TextView mDisplay;
+    GoogleCloudMessaging gcm;
+    AtomicInteger msgId = new AtomicInteger();
+    SharedPreferences prefs;
+    Context context;
+
+    String regid;
+
+    &#64;Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        setContentView(R.layout.main);
+        mDisplay = (TextView) findViewById(R.id.display);
+
+        context = getApplicationContext();
+
+        // Check device for Play Services APK. If check succeeds, proceed with
+        //  GCM registration.
+        if (checkPlayServices()) {
+            gcm = GoogleCloudMessaging.getInstance(this);
+            regid = getRegistrationId(context);
+
+            if (regid.isEmpty()) {
+                registerInBackground();
+            }
+        } else {
+            Log.i(TAG, "No valid Google Play Services APK found.");
+        }
+    }
+...
+}</pre>
+
+<p>The app calls {@code getRegistrationId()} to see whether there is an existing
+registration ID stored in shared preferences:</p>
+
+<pre>/**
+ * Gets the current registration ID for application on GCM service.
+ * &lt;p&gt;
+ * If result is empty, the app needs to register.
+ *
+ * &#64;return registration ID, or empty string if there is no existing
+ *         registration ID.
+ */
+private String getRegistrationId(Context context) {
+    final SharedPreferences prefs = getGCMPreferences(context);
+    String registrationId = prefs.getString(PROPERTY_REG_ID, "");
+    if (registrationId.isEmpty()) {
+        Log.i(TAG, "Registration not found.");
+        return "";
+    }
+    // Check if app was updated; if so, it must clear the registration ID
+    // since the existing regID is not guaranteed to work with the new
+    // app version.
+    int registeredVersion = prefs.getInt(PROPERTY_APP_VERSION, Integer.MIN_VALUE);
+    int currentVersion = getAppVersion(context);
+    if (registeredVersion != currentVersion) {
+        Log.i(TAG, "App version changed.");
+        return "";
+    }
+    return registrationId;
+}
+...
+/**
+ * &#64;return Application's {&#64;code SharedPreferences}.
+ */
+private SharedPreferences getGCMPreferences(Context context) {
+    // This sample app persists the registration ID in shared preferences, but
+    // how you store the regID in your app is up to you.
+    return getSharedPreferences(DemoActivity.class.getSimpleName(),
+            Context.MODE_PRIVATE);
+}</pre>
+
+<p>If the registration ID doesn't exist or the app was updated,
+{@code getRegistrationId()} returns an empty string
+to indicate that the app needs to get a new regID. {@code getRegistrationId()} calls
+the following method to check the app version:</p>
+
+<pre>/**
+ * &#64;return Application's version code from the {&#64;code PackageManager}.
+ */
+private static int getAppVersion(Context context) {
+    try {
+        PackageInfo packageInfo = context.getPackageManager()
+                .getPackageInfo(context.getPackageName(), 0);
+        return packageInfo.versionCode;
+    } catch (NameNotFoundException e) {
+        // should never happen
+        throw new RuntimeException("Could not get package name: " + e);
+    }
+}</pre>
+
+
+<p>If there isn't a valid existing registration ID, {@code DemoActivity} calls the
+following {@code registerInBackground()} method to register. Note that because the GCM
+methods {@code register()} and {@code unregister()} are blocking, this has to
+take place on a background thread. This sample uses {@link android.os.AsyncTask}
+to accomplish this:</p>
+
+<pre>
+/**
+ * Registers the application with GCM servers asynchronously.
+ * &lt;p&gt;
+ * Stores the registration ID and app versionCode in the application's
+ * shared preferences.
+ */
+private void registerInBackground() {
+    new AsyncTask<Void, Void, String>() {
+        &#64;Override
+        protected String doInBackground(Void... params) {
+            String msg = "";
+            try {
+                if (gcm == null) {
+                    gcm = GoogleCloudMessaging.getInstance(context);
+                }
+                regid = gcm.register(SENDER_ID);
+                msg = "Device registered, registration ID=" + regid;
+
+                // You should send the registration ID to your server over HTTP,
+                // so it can use GCM/HTTP or CCS to send messages to your app.
+                // The request to your server should be authenticated if your app
+                // is using accounts.
+                sendRegistrationIdToBackend();
+
+                // For this demo: we don't need to send it because the device
+                // will send upstream messages to a server that echo back the
+                // message using the 'from' address in the message.
+
+                // Persist the regID - no need to register again.
+                storeRegistrationId(context, regid);
+            } catch (IOException ex) {
+                msg = "Error :" + ex.getMessage();
+                // If there is an error, don't just keep trying to register.
+                // Require the user to click a button again, or perform
+                // exponential back-off.
+            }
+            return msg;
+        }
+
+        &#64;Override
+        protected void onPostExecute(String msg) {
+            mDisplay.append(msg + "\n");
+        }
+    }.execute(null, null, null);
+    ...
+    /**
+     * Sends the registration ID to your server over HTTP, so it can use GCM/HTTP
+     * or CCS to send messages to your app. Not needed for this demo since the
+     * device sends upstream messages to a server that echoes back the message
+     * using the 'from' address in the message.
+     */
+    private void sendRegistrationIdToBackend() {
+      // Your implementation here.
+    }
+}</pre>
+
+<p>After registering, the app calls {@code storeRegistrationId()} to store the
+registration ID in shared preferences for future use. This is just one way of
+persisting a regID. You might choose to use a different approach in your app:</p>
+
+<pre>/**
+ * Stores the registration ID and app versionCode in the application's
+ * {&#64;code SharedPreferences}.
+ *
+ * &#64;param context application's context.
+ * &#64;param regId registration ID
+ */
+private void storeRegistrationId(Context context, String regId) {
+    final SharedPreferences prefs = getGCMPreferences(context);
+    int appVersion = getAppVersion(context);
+    Log.i(TAG, "Saving regId on app version " + appVersion);
+    SharedPreferences.Editor editor = prefs.edit();
+    editor.putString(PROPERTY_REG_ID, regId);
+    editor.putInt(PROPERTY_APP_VERSION, appVersion);
+    editor.commit();
+}</pre>
+
+<h3 id="sample-send">Send a message</h3>
+<p>When the user clicks the app's <strong>Send</strong> button, the app sends an
+upstream message using the
+<a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">
+{@code GoogleCloudMessaging}</a> APIs. In order to receive the upstream message,
+your server should be connected to CCS. You can use one of the demo servers in
+<a href="ccs.html#implement">Implementing an XMPP-based App Server</a> to run the sample and connect
+to CCS.</p>
+
+<pre>public void onClick(final View view) {
+    if (view == findViewById(R.id.send)) {
+        new AsyncTask<Void, Void, String>() {
+            &#64;Override
+            protected String doInBackground(Void... params) {
+                String msg = "";
+                try {
+                    Bundle data = new Bundle();
+                        data.putString("my_message", "Hello World");
+                        data.putString("my_action",
+                                "com.google.android.gcm.demo.app.ECHO_NOW");
+                        String id = Integer.toString(msgId.incrementAndGet());
+                        gcm.send(SENDER_ID + "@gcm.googleapis.com", id, data);
+                        msg = "Sent message";
+                } catch (IOException ex) {
+                    msg = "Error :" + ex.getMessage();
+                }
+                return msg;
+            }
+
+            &#64;Override
+            protected void onPostExecute(String msg) {
+                mDisplay.append(msg + "\n");
+            }
+        }.execute(null, null, null);
+    } else if (view == findViewById(R.id.clear)) {
+        mDisplay.setText("");
+    }
+}</pre>
+
+<h3 id="sample-receive">Receive a message</h3>
+
+<p>As described above in <a href="#manifest">Step 2</a>, the app includes a
+{@link android.support.v4.content.WakefulBroadcastReceiver} for the <code>com.google.android.c2dm.intent.RECEIVE</code>
+intent. A broadcast receiver is the mechanism GCM uses to deliver messages. When {@code onClick()}
+calls {@code gcm.send()}, it triggers the broadcast receiver's {@code onReceive()}
+method, which has the responsibility of making sure that the GCM message gets handled.</p>
+<p>A {@link android.support.v4.content.WakefulBroadcastReceiver} is a special type of
+broadcast receiver that takes care of
+creating and managing a
+<a href="{@docRoot}reference/android/os/PowerManager.html#PARTIAL_WAKE_LOCK">
+partial wake lock</a> for your app.
+It passes off the work of processing the GCM message to a
+{@link android.app.Service} (typically an
+{@link android.app.IntentService}), while ensuring that the device does not
+go back to sleep in the transition. If you don't hold a wake lock while transitioning
+the work to a service, you are effectively allowing the device to go back to sleep before
+the work completes. The net result is that the app might not finish processing
+the GCM message until some arbitrary point in the future, which is not what you want.</p>
+
+<p class="note"><strong>Note:</strong> Using {@link android.support.v4.content.WakefulBroadcastReceiver}
+is not a requirement. If you have a relatively simple app that doesn't require
+a service, you can intercept the GCM message in a regular {@link android.content.BroadcastReceiver}
+and do your processing there. Once you get the intent that GCM passes into
+your broadcast receiver's {@code onReceive()} method, what you do with it
+is up to you.</p>
+
+<p>This snippet starts {@code GcmIntentService} with the method
+{@link android.support.v4.content.WakefulBroadcastReceiver#startWakefulService startWakefulService()}.
+This method is comparable to {@link android.content.Context#startService startService()}, except that
+the {@link android.support.v4.content.WakefulBroadcastReceiver} is holding a
+wake lock when the service starts. The intent that is passed with
+{@link android.support.v4.content.WakefulBroadcastReceiver#startWakefulService startWakefulService()}
+holds an extra identifying the wake lock:</p>
+
+
+<pre>public class GcmBroadcastReceiver extends WakefulBroadcastReceiver {
+    &#64;Override
+    public void onReceive(Context context, Intent intent) {
+        // Explicitly specify that GcmIntentService will handle the intent.
+        ComponentName comp = new ComponentName(context.getPackageName(),
+                GcmIntentService.class.getName());
+        // Start the service, keeping the device awake while it is launching.
+        startWakefulService(context, (intent.setComponent(comp)));
+        setResultCode(Activity.RESULT_OK);
+    }
+}</pre>
+
+<p>The intent service shown below does the actual work of handling the GCM
+message. When the service is finished, it calls
+{@link android.support.v4.content.WakefulBroadcastReceiver#completeWakefulIntent GcmBroadcastReceiver.completeWakefulIntent()}
+to release the wake lock. The
+{@link android.support.v4.content.WakefulBroadcastReceiver#completeWakefulIntent completeWakefulIntent()}
+method has as its parameter the same intent that was
+passed in from the {@link android.support.v4.content.WakefulBroadcastReceiver}.
+</p>
+
+<p>This snippet processes the GCM message based on message type, and posts the
+result in a notification. But what you do with GCM messages in your app is up to
+you&mdash;the possibilities are endless. For example, the message might be a ping,
+telling the app to sync to a server to retrieve new content, or it might be a
+chat message that you display in the UI.</p>
+
+<pre>
+public class GcmIntentService extends IntentService {
+    public static final int NOTIFICATION_ID = 1;
+    private NotificationManager mNotificationManager;
+    NotificationCompat.Builder builder;
+
+    public GcmIntentService() {
+        super("GcmIntentService");
+    }
+
+    &#64;Override
+    protected void onHandleIntent(Intent intent) {
+        Bundle extras = intent.getExtras();
+        GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this);
+        // The getMessageType() intent parameter must be the intent you received
+        // in your BroadcastReceiver.
+        String messageType = gcm.getMessageType(intent);
+
+        if (!extras.isEmpty()) {  // has effect of unparcelling Bundle
+            /*
+             * Filter messages based on message type. Since it is likely that GCM
+             * will be extended in the future with new message types, just ignore
+             * any message types you're not interested in, or that you don't
+             * recognize.
+             */
+            if (GoogleCloudMessaging.
+                    MESSAGE_TYPE_SEND_ERROR.equals(messageType)) {
+                sendNotification("Send error: " + extras.toString());
+            } else if (GoogleCloudMessaging.
+                    MESSAGE_TYPE_DELETED.equals(messageType)) {
+                sendNotification("Deleted messages on server: " +
+                        extras.toString());
+            // If it's a regular GCM message, do some work.
+            } else if (GoogleCloudMessaging.
+                    MESSAGE_TYPE_MESSAGE.equals(messageType)) {
+                // This loop represents the service doing some work.
+                for (int i=0; i<5; i++) {
+                    Log.i(TAG, "Working... " + (i+1)
+                            + "/5 @ " + SystemClock.elapsedRealtime());
+                    try {
+                        Thread.sleep(5000);
+                    } catch (InterruptedException e) {
+                    }
+                }
+                Log.i(TAG, "Completed work @ " + SystemClock.elapsedRealtime());
+                // Post notification of received message.
+                sendNotification("Received: " + extras.toString());
+                Log.i(TAG, "Received: " + extras.toString());
+            }
+        }
+        // Release the wake lock provided by the WakefulBroadcastReceiver.
+        GcmBroadcastReceiver.completeWakefulIntent(intent);
+    }
+
+    // Put the message into a notification and post it.
+    // This is just one simple example of what you might choose to do with
+    // a GCM message.
+    private void sendNotification(String msg) {
+        mNotificationManager = (NotificationManager)
+                this.getSystemService(Context.NOTIFICATION_SERVICE);
+
+        PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
+                new Intent(this, DemoActivity.class), 0);
+
+        NotificationCompat.Builder mBuilder =
+                new NotificationCompat.Builder(this)
+        .setSmallIcon(R.drawable.ic_stat_gcm)
+        .setContentTitle("GCM Notification")
+        .setStyle(new NotificationCompat.BigTextStyle()
+        .bigText(msg))
+        .setContentText(msg);
+
+        mBuilder.setContentIntent(contentIntent);
+        mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
+    }
+}</pre>
+
+<h2 id="run">Running the Sample</h2>
+
+<p>To run the sample:</p>
+
+<ol>
+  <li>Follow the instructions in <a href="gs.html">Getting Started</a> to get your sender ID and
+  API key.</li>
+  <li>Implement your client app, as described in this document. You can find the complete source
+  code for the client app at the <a href="http://code.google.com/p/gcm">open source site</a>.</li>
+  <li>Run one of the demo servers (Java or Python) provided in
+<a href="ccs.html#implement">Implementing an XMPP-based App Server</a>. Whichever demo server you
+ choose, don't forget to edit its code before running it to supply
+your sender ID and API key.
+</li>
+
+</ol>
+
+<h2 id="stats">Viewing Statistics</h2>
+
+<p>To view  statistics and any error messages for your GCM applications:</p>
+<ol>
+  <li> Go to the <code><a href="http://play.google.com/apps/publish">Developer Console</a></code>.</li>
+  <li>Login with your developer account.
+  <p>You will see a page that has a list of all of your apps.</p></li>
+  <li> Click on the &quot;statistics&quot; link next to the app for which you
+want to view GCM stats.
+  <p>Now you are on the statistics page.</p> </li>
+  <li>Go to the drop-down menu and select the GCM metric you want to view.
+  </li>
+</ol>
+<p class="note"><strong>Note:</strong> Stats on the Google API Console are not
+enabled for GCM. You must use the <a href="http://play.google.com/apps/publish">Developer Console</a>.</p>
 
 
diff --git a/docs/html/google/gcm/gcm.jd b/docs/html/google/gcm/gcm.jd
index ceb82b0..3c80b5f 100644
--- a/docs/html/google/gcm/gcm.jd
+++ b/docs/html/google/gcm/gcm.jd
@@ -1,48 +1,23 @@
-page.title=GCM Architectural Overview
+page.title=Overview
 @jd:body
 
 <div id="qv-wrapper">
 <div id="qv">
 
-<h2>Quickview</h2>
-
-<ul>
-<li>Get an introduction to key GCM terms and concepts.</li>
-<li>Learn the basic features of a GCM application.</li>
-<li>Understand the role of the 3rd-party application server, and how to send messages and process results.</li>
-</ul>
-
-
 <h2>In this document</h2>
 
 <ol class="toc">
-  <li><a href="#intro">Introduction</a> </li>
-  <li><a href="#arch">Architectural Overview</a>
-    <ol>
-      <li><a href="#lifecycle">Lifecycle Flow</a></li>
-        <ol>
-          <li><a href="#register">Enable GCM</a></li>
-          <li><a href="#push-process">Send a message</a></li>
-          <li><a href="#receiving">Receive a message</a></li>
-        </ol>
-      <li><a href="#user">What Does the User See?</a></li>
-    </ol>
-  </li>
-  <li><a href="#server">Role of  the 3rd-party Application Server</a>
+  <li><a href="#key">Key Concepts</a></li>
+  <li><a href="#arch">Architectural Overview</a></li>
+  <li><a href="#lifecycle">Lifecycle Flow</a>
     <ol class="toc">
-      <li><a href="#send-msg">Sending Messages</a>
-        <ol>
-          <li><a href="#request">Request format</a></li>
-          <li><a href="#response">Response format</a></li>
-        </ol>
-      </li>
+      <li><a href="#register">Enable GCM</a></li>
+      <li><a href="#push-process">Send a message</a></li>
+      <li><a href="#receiving">Receive a message</a></li>
     </ol>
-    <li><a href="#stats">Viewing Statistics</a>
   </li>
 </ol>
 
-
-
 </div>
 </div>
 
@@ -50,24 +25,15 @@
 developers  send data from servers to their Android applications on  Android
 devices, and upstream messages from the user's device back to the cloud.
 This could be a lightweight message telling the Android application
-that there is new data to be fetched from the server (for instance, a movie
-uploaded by a friend), or it could be a message containing up to 4kb of payload
+that there is new data to be fetched from the server (for instance, a "new email"
+notification informing the application that it is out of sync with the back end),
+or it could be a message containing up to 4kb of payload
 data (so apps like instant messaging can consume the message directly). The GCM
 service handles all aspects  of queueing of messages and delivery to the target
 Android application running  on the target device.</p>
-
-<p>GCM introduces GCM Cloud Connection Server (CCS), which you can use
-in tandem with GCM HTTP service/endpoint/APIs.
-CCS uses XMPP, and it offers asynchronous, bidirectional
-messaging. For more information, see
-<a href="ccs.html">GCM Cloud Connection Server</a>.
-  
   
 <p class="note"> To jump right into using GCM with your Android
-  applications, see the instructions in <a href="gs.html">Getting Started</a>.</p>
-
-
-<h2 id="intro">Introduction</h2>
+  applications, see <a href="gs.html">Getting Started</a>.</p>
 
 <p>Here are the primary characteristics of Google Cloud 
 Messaging (GCM):</p>
@@ -75,9 +41,11 @@
 <ul>
   <li>It allows 3rd-party application servers to send messages to
 their Android applications.</li>
-  <li>Using the <a href="ccs.html">GCM Cloud Connection Server</a>, you can receive upstream messages from the user's device.</li>
+  <li>Using the <a href="ccs.html">GCM Cloud Connection Server</a>, you can receive
+upstream messages from the user's device.</li>
   <li>An Android application on an Android device doesn't need to be running to receive
-messages. The system will wake up the Android application via Intent broadcast when the  message arrives, as long as the application is set up with the proper
+messages. The system will wake up the Android application via Intent broadcast
+when the  message arrives, as long as the application is set up with the proper
 broadcast receiver and permissions.</li>
   <li>It does not provide any  built-in user interface or other handling for
 message data. GCM  simply passes raw message data received straight to the
@@ -85,57 +53,67 @@
 application might post a notification, display a custom user interface, or 
 silently sync data.</li>
   <li>It requires devices running Android 2.2 or higher that also have the
-Google Play Store application installed, or or an emulator running Android 2.2 with Google APIs. However, you are not limited to deploying your
+Google Play Store application installed, or or an emulator running Android 2.2
+with Google APIs. However, you are not limited to deploying your
 Android applications through Google Play Store.</li>
-  <li>It uses an existing connection for Google services. For pre-3.0 devices, this requires users to
-set up their Google account on their mobile devices. A Google account is not a requirement on devices running Android 4.0.4 or higher.</li>
+  <li>It uses an existing connection for Google services. For pre-3.0 devices,
+this requires users to
+set up their Google account on their mobile devices. A Google account is not a
+requirement on devices running Android 4.0.4 or higher.</li>
 </ul>
-<h2 id="arch">Architectural Overview</h2>
-<p>This section gives an overview of how GCM works. </p>
+
+<h2 id="key">Key Concepts</h2>
+
 <p>This table summarizes the key terms and concepts involved in GCM. It is
 divided into these categories:</p>
 <ul>
-  <li><strong>Components</strong> &mdash; The physical entities that play a role in
+  <li><strong>Components</strong> &mdash; The entities that play a primary role in
 GCM.</li>
   <li><strong>Credentials</strong> &mdash; The IDs and tokens that are used in
 different stages of GCM to ensure that all parties have been authenticated, and
 that the message is going to the correct place.</li>
 </ul>
 
+<p class="table-caption" id="table1">
+  <strong>Table 1.</strong> GCM components and credentials.</p>
+
 <table>
   <tr>
     <th colspan="2">Components</th>
   </tr>
   <tr>
-    <td width="165"><strong>Mobile Device</strong></td>
-    <td width="1176">The device that is running an Android application that uses
-GCM. This must be a 2.2 Android device that has Google Play Store installed, and it must
-have at least one logged in Google account if the device is running a version lower than Android 4.0.4. Alternatively, for testing you can use an emulator running Android 2.2 with Google APIs.</td>
+    <td width="165"><strong>Client App</strong></td>
+    <td width="1176">The GCM-enabled Android application that is running on a
+    device. This must be a 2.2 Android device that has Google Play Store installed, and it must
+have at least one logged in Google account if the device is running a version
+lower than Android 4.0.4. Alternatively, for testing you can use an emulator
+running Android 2.2 with Google APIs.</td>
   </tr>
   <tr>
     <td><strong>3rd-party Application Server</strong></td>
-    <td>An application server that  developers  set up as part of implementing
-GCM in their applications. The 3rd-party application server sends data to an
-Android application on the device via the GCM server.</td>
+    <td>An application server that you write as part of implementing
+GCM. The 3rd-party application server sends data to an
+Android application on the device via the GCM connection server.</td>
   </tr>
   <tr>
-    <td><strong>GCM Servers</strong></td>
-    <td>The Google servers involved in taking messages from the 3rd-party
+    <td><strong>GCM Connection Servers</strong></td>
+    <td>The Google-provided servers involved in taking messages from the 3rd-party
 application server and sending them to the device. </td>
   </tr>
   <tr>
-    <th colspan="2"><strong>Credentials</strong></th>
+    <th colspan="2">Credentials</th>
   </tr>
   <tr>
     <td><strong>Sender ID</strong></td>
-    <td>A project number you acquire from the API console, as described in <a href="gs.html#create-proj">Getting Started</a>. The sender
-ID is used in the <a href="#registering">registration process</a> to identify an
-Android application that is permitted to send messages to the device.</td>
+    <td>A project number you acquire from the API console, as described in
+<a href="gs.html#create-proj">Getting Started</a>. The sender
+ID is used in the <a href="#register">registration process</a> to identify a
+3rd-party application server that is permitted to send messages to the device.</td>
   </tr>
   <tr>
     <td><strong>Application ID</strong></td>
     <td>The Android application that is registering to receive messages. The Android application
-is identified by the package name from the <a href="#manifest">manifest</a>.
+is identified by the package name from the <a href="client.html#manifest">manifest</a>.
 This  ensures that the messages are targeted to the correct Android application.</td>
   </tr>
   <tr>
@@ -158,7 +136,8 @@
   </tr>
   <tr>
     <td><strong>Google User Account</strong></td>
-    <td>For GCM to work, the mobile device must include at least one Google account if the device is running a version lower than Android 4.0.4.</td>
+    <td>For GCM to work, the mobile device must include at least one Google
+account if the device is running a version lower than Android 4.0.4.</td>
   </tr>
   <tr>
     <td><strong>Sender Auth Token</strong></td>
@@ -167,25 +146,46 @@
 The API key is included in the header of POST requests  that send messages.</td>
   </tr>
 
-  <tr>
-    <td><strong>Notification Key</strong></td>
-    <td>Part of the user notifications feature, which provides a mapping between a user and instances of an app running on multiple devices owned by the user. The {@code notification_key} is the token that GCM uses to fan out notifications to all devices whose registration IDs are associated with the key. For more discussion of this topic, see <a href="notifications.html">User Notifications</a>.</td>
-  </tr>
-
-<tr>
-    <td><strong>Notification Key Name</strong></td>
-    <td>Part of the user notifications feature. The {@code notification_key_name} is a name or identifier (can be a username for a 3rd-party app) that is unique to a given user. It is used by third parties to group together registration IDs for a single user. For more discussion of this topic, see <a href="notifications.html">User Notifications</a>.</td>
-  </tr>
-
 </table>
 
-<h3 id="lifecycle">Lifecycle Flow</h3>
+<h2 id="arch">Architectural Overview</h2>
+
+<p>A GCM implementation includes a Google-provided
+connection server, a 3rd-party app server that interacts with the connection
+server, and a GCM-enabled client app running on an Android device:</p>
+
+<img src="{@docRoot}images/gcm/GCM-arch.png">
+
+<p class="img-caption">
+  <strong>Figure 1.</strong> GCM Architecture.
+</p>
+
+<p>This is how these components interact:</p>
+<ul>
+  <li>Google-provided <strong>GCM Connection Servers</strong> take messages from
+a 3rd-party application server and send these messages to a
+GCM-enabled Android application (the &quot;client app&quot;) running on a device.
+Currently Google provides connection servers for <a href="http.html">HTTP</a>
+and <a href="ccs.html">XMPP</a>.</li>
+  <li>The <strong>3rd-Party Application Server</strong> is a component that you
+implement to work with your chosen GCM connection server(s). App servers send
+messages to a GCM connection server; the connection server enqueues and stores the
+message, and then sends it to the device when the device is online.
+For more information, see <a href="server.html">Implementing GCM Server</a>.</li>
+  <li>The <strong>Client App</strong> is a GCM-enabled Android application running
+on a device. To receive GCM messages, this app must register with GCM and get a
+registration ID. If you are using the <a href="ccs.html">XMPP</a> (CCS) connection
+server, the client app can send "upstream" messages back to the connection server.
+For more information on how to implement the client app, see
+<a href="client.html">Implementing GCM Client</a>.</li>
+</ul>
+
+<h2 id="lifecycle">Lifecycle Flow</h2>
 
 <ul>
   <li><a href="#register">Enable GCM</a>. An Android application running on a
 mobile device registers to receive messages.</li>
- <li><a href="notifications.html">User Notifications</a>. A 3rd-party server can optionally group multiple registration IDs
-in a {@code notification_key} to send messages to multiple devices owned by a single user.</li>
+
   <li><a href="#push-process">Send a message</a>. A 3rd-party application
 server sends messages to the device.</li>
   <li><a href="#receiving">Receive a message</a>. An Android application
@@ -194,62 +194,18 @@
 
 <p>These processes are described in more detail below.</p>
 
-<h4 id="register">Enable GCM</h4>
+<h3 id="register">Enable GCM</h3>
 
-<p>This is the sequence of events that occurs when an Android application
-running on a mobile device registers to receive messages:<span
-class="red-text"></span></p>
-
-<ol>
-  <li>The first time the Android application needs to use the messaging service, it
-fires off a registration Intent to a GCM server.
-    <p>This registration Intent
-(<code>com.google.android.c2dm.intent.REGISTER</code>) includes the sender ID, and the Android application ID.</p>
-<p class="note"><strong>Note:</strong> Because there is no lifecycle method that is called when the application is run for
-the first time, the registration intent should be sent on <code>onCreate()</code>, but only if the application is not registered yet.
+<p>The first time the Android application needs to use the messaging service, it
+calls the <a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">
+{@code GoogleCloudMessaging}</a> method {@code register()}, as discussed in
+<a href="client.html">Implementing GCM Client</a>.
+The {@code register()} method returns a registration ID. The Android
+application should store this ID for later use (for instance,
+to check in <code>onCreate()</code> if it is already registered).
 </p>
-  </li>
-  <li>If the registration is successful, the GCM server broadcasts a <code>com.google.android.c2dm.intent.REGISTRATION</code> intent which gives the Android application  a registration
-ID. 
-    <p>The Android application should store this ID for later use (for instance, to check on <code>onCreate()</code> if it is already registered).
-Note that Google may periodically refresh the registration ID, so you should design your Android application
-with the understanding that the <code>com.google.android.c2dm.intent.REGISTRATION</code> intent may be called
-multiple times. Your Android application needs to be able to respond
-accordingly.</p></li>
-  <li>To complete the registration, the Android application sends the registration ID to
-the application server. The application server typically stores the registration
-ID in a database. </li>
-</ol>
 
-<p>The registration ID lasts until the Android application explicitly unregisters
-itself, or until Google refreshes the registration ID for your Android application.</p>
-
-<p class="note"><strong>Note:</strong> When users uninstall an application, it is not automatically unregistered on GCM. It is only  unregistered when the GCM server tries to send a message to the device and the device answers that the application is uninstalled or it does not have a broadcast receiver configured to receive <code>com.google.android.c2dm.intent.RECEIVE</code> intents. At that point, your server should mark the device as unregistered (the server will receive a <code><a href="#unreg_device">NotRegistered</a></code> error).</p>
-  <p>
-Note that it might take a few minutes for the registration ID to be completely removed from the GCM server. So if the 3rd-party server sends a message during this time, it will get a valid message ID, even though the message will not be delivered to the device.</p>
-
-
-
-
-<h4 id="push-process">Send a Message</h4>
-
-<p>For an application server to send a  message to an Android application, the following things must be in
-place:</p>
-
-<ul>
-  <li>The Android application has stored a target that it can specify as the recipient of a message. This can be one of the following:
-  <ul>
-    <li>A single registration ID (or an array of registration IDs) that allows the app to receive messages
-for a particular device.</li>
-    <li>A {@code notification_key} and corresponding {@code notification_key_name}, used to map a single user to multiple registration IDs. For more discussion of this topic, see <a href="notifications.html">User Notifications</a>.</li>
-  </ul>
-    </li>
-
-<li>An API key. This is something that the developer must have already
-set up on the application server for the Android application (for more discussion, see
-<a href="#server">Role of the 3rd-party Application Server</a>). Now it will
-get used to send messages to the device. </li>
-</ul>
+<h3 id="push-process">Send a message</h3>
 
 <p>Here is the sequence of events that occurs when the application server sends a 
 message:</p>
@@ -264,13 +220,14 @@
 targeted Android application gets the message. This wakes the Android application up. The
 Android application does not need to be running beforehand to receive the message.</li>
   <li>The Android application processes the message. If the Android application is doing
-non-trivial processing, you may want to grab a {@link android.os.PowerManager.WakeLock} and do any processing in a Service.</li>
+non-trivial processing, you may want to grab a
+{@link android.os.PowerManager.WakeLock} and do any processing in a service.</li>
 </ol>
 
 <p> An Android application can  unregister GCM if it no longer wants to receive 
 messages.</p>
 
-<h4 id="receiving">Receive a Message</h4>
+<h3 id="receiving">Receive a message</h3>
 
 <p>This is the sequence of events that occurs when an Android application
 installed on a mobile device receives a message:</p>
@@ -282,482 +239,8 @@
 in a <code>com.google.android.c2dm.intent.RECEIVE</code> Intent as a set of
 extras.</li>
   <li>The Android application extracts the raw data
-from the <code>com.google.android.c2dm.intent.RECEIVE</code><code> </code>Intent by key and processes the data.</li>
+from the <code>com.google.android.c2dm.intent.RECEIVE</code><code> </code>Intent
+by key and processes the data.</li>
 </ol>
 
-<h3 id="user">What Does the User See?</h3>
-
-<p>When mobile device users install Android applications that include GCM, the Google Play Store will inform them that the Android application
-includes GCM. They must approve the use of this feature to install the
-Android application. </p>
-
-
-<h2 id="server">Role of the 3rd-party Application Server</h2>
-
-<p>Before you can write client Android applications that use the GCM feature, you must
-have an  application server that meets the following criteria:</p>
-
-<ul>
-  <li>Able to communicate with your client.</li>
-  <li>Able to  fire off HTTPS requests to the GCM server.</li>
-  <li>Able to handle requests and resend them as needed, using <a href="http://en.wikipedia.org/wiki/Exponential_backoff">exponential back-off.</a></li>
-  <li>Able to store the API key and client registration IDs. The
-API key is included in the header of POST requests that send
-messages.</li>
-</ul>
-
-<h3 id="send-msg">Sending Messages</h3>
-<p>This section describes how the 3rd-party application server sends messages to one or more mobile devices. Note the following:</p>
-<ul>
-  <li>A 3rd-party application server can either send messages to a single device or to multiple devices. A message sent to multiple devices simultaneously is called a <em>multicast message</em>.</li>
-  <li>To send a single message to multiple devices owned by a single user, you can use a {@code notification_key}, as described in <a href="notifications.html">User Notifications</a>.
-  
-  <li>You have 2 choices in how you construct requests and responses: plain text or JSON.</li>
-  <li>However, to send multicast messages, you must use JSON. Plain text will not work.</li>
-</ul>
-<p>Before the 3rd-party application server can send a  message to an
-  Android application, it must have received a registration ID from it.</p>
-<h4 id="request">Request format</h4>
-<p>To send a  message, the application server issues a POST request to <code>https://android.googleapis.com/gcm/send</code>.</p>
-<p>A  message request is made of 2 parts: HTTP header and HTTP body.</p>
-
-<p>The HTTP header must contain the following headers:</p>
-<ul>
-  <li><code>Authorization</code>: key=YOUR_API_KEY</li>
-  <li><code>Content-Type</code>: <code>application/json</code> for JSON; <code>application/x-www-form-urlencoded;charset=UTF-8</code> for plain text.
-  </li>
-</ul>
-
-<p>For example:
-</p>
-<pre>Content-Type:application/json
-Authorization:key=AIzaSyB-1uEai2WiUapxCs2Q0GZYzPu7Udno5aA
-
-{
-  "registration_ids" : ["APA91bHun4MxP5egoKMwt2KZFBaFUH-1RYqx..."],
-  "data" : {
-    ...
-  },
-}</pre>
-<p class="note">
-  <p><strong>Note:</strong> If <code>Content-Type</code> is omitted, the format is assumed to be plain text.</p>
-</p>
-
-<p>The HTTP body content depends on whether you're using JSON or plain text. For JSON, it must contain a string representing a JSON object with the following fields:</p>
-<table>
-  <tr>
-    <th>Field</th>
-    <th>Description</th>
-  </tr>
-  <tr>
-    <td><code>registration_ids</code></td>
-    <td>A string array with the list of devices (registration IDs) receiving the message. It must contain at least 1 and at most 1000 registration IDs. To send a multicast message, you must use JSON. For sending a single message to a single device, you could use a JSON object with just 1 registration id, or plain text (see below). A request must include a recipient&mdash;this can be either a registration ID, an array of registration IDs, or a {@code notification_key}.</td>
-  </tr>
- <tr>
-    <td><code>notification_key</code></td>
-    <td>A string that maps a single user to multiple registration IDs associated with that user. This
-allows a 3rd-party server to send a single message to multiple app instances (typically on multiple devices) owned by a single user. A 3rd-party server can use {@code notification_key} as the target for a message instead of an individual registration ID (or array of registration IDs). The maximum number of members allowed for a {@code notification_key} is 10. For more discussion of this topic, see <a href="notifications.html">User Notifications</a>. Optional.</td>
-  </tr>
-
-<tr>
-    <td><code>notification_key_name</code></td>
-    <td>A name or identifier (can be a username for a 3rd-party app) that is unique to a given user. It is used by 3rd parties to group together registration IDs for a single user. The <code>notification_key_name</code> should be uniquely named per app in case you have multiple apps for the same project ID. This ensures that notifications only go to the intended target app. For more discussion of this topic, see <a href="notifications.html">User Notifications</a>.</td>
-  </tr>
-
-  <tr>
-    <td><code>collapse_key</code></td>
-    <td>An arbitrary string (such as &quot;Updates Available&quot;) that is used to collapse a group of like messages
-when the device is offline, so that only the last message gets sent to the
-client. This is intended to avoid sending too many messages to the phone when it
-comes back online. Note that since there is no guarantee of the order in which
-messages get sent, the &quot;last&quot; message may not actually be the last
-message sent by the application server. See <a href="adv.html#collapsible">Advanced Topics</a> for more discussion of this topic. Optional.</td>
-  </tr>
-  <tr>
-    <td><code>data</code></td>
-    <td>A JSON object whose fields represents the key-value pairs of the message's payload data. If present, the payload data it will be
-included in the Intent as application data, with the key being the extra's name. For instance, <code>"data":{"score":"3x1"}</code> would result in an intent extra named <code>score</code> whose value is the string <code>3x1</code>. 
-
-There is no limit on the number of key/value pairs, though there is a limit on the total size of the message (4kb). The values could be any JSON object, but we recommend using strings, since the values will be converted to strings in the GCM server anyway. If you want to include objects or other non-string data types (such as integers or booleans), you have to do the conversion to string yourself. Also note that the key cannot be a reserved word (<code>from</code> or any word starting with <code>google.</code>). To complicate things slightly, there are some reserved words (such as <code>collapse_key</code>) that are technically allowed in payload data. However, if the request also contains the word, the value in the request will overwrite the value in the payload data. Hence using words that are defined as field names in this table is not recommended, even in cases where they are technically allowed. Optional.</td>
-
-
-  </tr>
-  <tr>
-    <td><code>delay_while_idle</code></td>
-    <td>If included, indicates that the message should not be sent immediately
-if the device is idle. The server will wait for the device to become active, and
-then only the last message for each <code>collapse_key</code> value will be
-sent. Optional. The default value is <code>false</code>, and must be a JSON boolean.</td>
-  </tr>
-  <tr>
-    <td><code>time_to_live</code></td>
-    <td>How long (in seconds) the message should be kept on GCM storage if the device is offline. Optional (default time-to-live is 4 weeks, and must be set as a JSON number).</td>
-  </tr>
-<tr>
-  <td><code>restricted_package_name</code></td>
-  <td>A string containing the package name of your application. When set, messages will only be sent to registration IDs that match the package name. Optional.
-  </td>
-</tr>
-<tr>
-  <td><code>dry_run</code></td>
-  <td>If included, allows developers to test their request without actually sending a message. Optional. The default value is <code>false</code>, and must be a JSON boolean.
-  </td>
-</tr>
-</table>
-
-<p>If you are using plain text instead of JSON, the message fields must be set as HTTP parameters sent in the body, and their syntax is slightly different, as described below:
-<table>
-  <tr>
-    <th>Field</th>
-    <th>Description</th>
-  </tr>
-  <tr>
-    <td><code>registration_id</code></td>
-    <td>Must contain the registration ID of the single device receiving the message. Required.</td>
-  </tr>
-  <tr>
-    <td><code>collapse_key</code></td>
-    <td>Same as JSON (see previous table). Optional.</td>
-  </tr>
-  <tr>
-    <td><code>data.&lt;key&gt;</code></td>
-
-    <td>Payload data, expressed as parameters prefixed with <code>data.</code> and suffixed as the key. For instance, a parameter of <code>data.score=3x1</code> would result in an intent extra named <code>score</code> whose value is the string <code>3x1</code>. There is no limit on the number of key/value parameters, though there is a limit on the total size of the  message. Also note that the key cannot be a reserved word (<code>from</code> or any word starting with 
-<code>google.</code>). To complicate things slightly, there are some reserved words (such as <code>collapse_key</code>) that are technically allowed in payload data. However, if the request also contains the word, the value in the request will overwrite the value in the payload data. Hence using words that are defined as field names in this table is not recommended, even in cases where they are technically allowed. Optional.</td>
-
-  </tr>
-  <tr>
-    <td><code>delay_while_idle</code></td>
-    <td>Should be represented as <code>1</code> or <code>true</code> for <code>true</code>, anything else for <code>false</code>. Optional. The default value is <code>false</code>.</td>
-  </tr>
-  <tr>
-    <td><code>time_to_live</code></td>
-    <td>Same as JSON (see previous table). Optional.</td>
-  </tr>
-<tr>
-  <td><code>restricted_package_name</code></td>
-  <td>Same as JSON (see previous table). Optional.
-  </td>
-</tr>
-<tr>
-  <td><code>dry_run</code></td>
-  <td>Same as JSON (see previous table). Optional.
-  </td>
-</tr>
-</table>
-
-<p>If you want to test your request (either JSON or plain text) without delivering the message to the devices, you can set an optional HTTP or JSON parameter called <code>dry_run</code> with the value <code>true</code>. The result will be almost identical to running the request without this parameter, except that the message will not be delivered to the devices. Consequently, the response will contain fake IDs for the message and multicast fields (see <a href="#response">Response format</a>).</p>
-
-  <h4 id="example-requests">Example requests</h4>
-  <p>Here is the smallest possible request (a message without any parameters and just one recipient) using JSON:</p>
-  <pre class="prettyprint pretty-json">{ &quot;registration_ids&quot;: [ &quot;42&quot; ] }</pre>
-  
-  <p>And here the same example using plain text:</p>
-  <pre class="prettyprint">registration_id=42</pre>
-  
-  <p> Here is a message with a payload and 6 recipients:</p>
-  <pre class="prettyprint pretty-HTML">{ "data": {
-    "score": "5x1",
-    "time": "15:10"
-  },
-  "registration_ids": ["4", "8", "15", "16", "23", "42"]
-}</pre>
-  <p>Here is a message with all optional fields set and 6 recipients:</p>
-  <pre class="prettyprint pretty-json">{ "collapse_key": "score_update",
-  "time_to_live": 108,
-  "delay_while_idle": true,
-  "data": {
-    "score": "4x8",
-    "time": "15:16.2342"
-  },
-  "registration_ids":["4", "8", "15", "16", "23", "42"]
-}</pre>
-  <p>And here is the same message using plain-text format (but just 1 recipient):  </p>
-  
-  <pre class="prettyprint">collapse_key=score_update&amp;time_to_live=108&amp;delay_while_idle=1&amp;data.score=4x8&amp;data.time=15:16.2342&amp;registration_id=42
-  </pre>
-
-<p class="note"><strong>Note:</strong> If your organization has a firewall 
-that restricts the traffic to or 
-from the Internet, you need to configure it to allow connectivity with GCM in order for
-your Android devices to receive messages. 
-The ports to open are: 5228, 5229, and 5230. GCM typically only uses 5228, but
-it sometimes uses 5229 and 5230. GCM doesn't provide specific IPs, so you should allow
-your firewall to accept outgoing connections to all IP addresses
-contained in the IP blocks listed in Google's ASN of 15169.</p>
-
-
-<h4 id="response">Response format</h4>
-
-<p>There are two possible outcomes when trying to send a message:</p>
-<ul>
-  <li>The message is processed successfully.</li>
-  <li>The GCM server rejects the request.</li>
-</ul>
-
-<p>When the message is processed successfully, the HTTP response has a 200 status and the body contains more information about the status of the message (including possible errors). When the request is rejected, 
-the HTTP response contains a non-200 status code (such as 400, 401, or 503).</p>
-
-<p>The following table summarizes the statuses that the HTTP response header might contain. Click the troubleshoot link for advice on how to deal with each type of error.</p>
-<table border=1>
-  <tr>
-    <th>Response</th>
-    <th>Description</th>
-  </tr>
-  <tr>
-    <td>200</td>
-    <td>Message was processed successfully. The response body will contain more details about the message status, but its format will depend whether the request was JSON or plain text. See <a href="#success">Interpreting a success response</a> for more details.</td>
-  </tr>
-  <tr>
-    <td>400</td>
-    <td><span id="internal-source-marker_0.2">Only applies for JSON requests. Indicates that the request could not be parsed as JSON, or it contained invalid fields (for instance, passing a string where a number was expected). The exact failure reason is described in the response and the problem should be addressed before the request can be retried.</td>
-  </tr>
-  <tr>
-    <td>401</td>
-    <td>There was an error authenticating the sender account. <a href="#auth_error">Troubleshoot</a></td>
-  </tr>
-  <tr>
-    <td>5xx</td>
-    <td>Errors in the 500-599 range (such as 500 or 503) indicate that there was an internal error in the GCM server while trying to process the request, or that the server is temporarily unavailable (for example, because of timeouts). Sender must retry later, honoring any <code>Retry-After</code> header included in the response. Application servers must implement exponential back-off. <a href="#internal_error">Troubleshoot</a></td>
-  </tr>
-</table>
-
-<h4 id="success">Interpreting a success response</h4>
-<p>When a JSON request is successful (HTTP status code 200), the response body contains a JSON object with the following fields:</p>
-<table>
-  <tr>
-    <th>Field</th>
-    <th>Description</th>
-  </tr>
-  <tr>
-    <td><code>multicast_id</code></td>
-    <td>Unique ID (number) identifying the multicast message.</td>
-  </tr>
-  <tr>
-    <td><code>success</code></td>
-    <td>Number of messages that were processed without an error.</td>
-  </tr>
-  <tr>
-    <td><code>failure</code></td>
-    <td>Number of messages that could not be processed.</td>
-  </tr>
-  <tr>
-    <td><code>canonical_ids</code></td>
-    <td>Number of results that contain a canonical registration ID. See <a href="adv.html#canonical">Advanced Topics</a> for more discussion of this topic.</td>
-  </tr>
-  <tr>
-    <td><code>results</code></td>
-    <td>Array of objects representing the status of the messages processed. The objects are listed in the same order as the request (i.e., for each registration ID in the request, its result is listed in the same index in the response) and they can have these fields:<br>
-      <ul>
-        <li><code>message_id</code>: String representing the message when it was successfully processed.</li>
-        <li><code>registration_id</code>: If set,  means that GCM processed the message but it has another canonical registration ID for that device, so sender should replace the IDs on future requests (otherwise they might be rejected). This field is never set if there is an error in the request.
-        </li>
-        <li><code>error</code>: String describing an error that occurred while processing the message for that recipient. The possible values are the same as documented in the above table, plus &quot;Unavailable&quot;  (meaning GCM servers were busy and could not process the message for that  particular recipient, so it could be retried).</li>
-    </ul></td>
-  </tr>
-</table>
-<p>If the value of <code>failure</code> and <code>canonical_ids</code> is 0, it's not necessary to parse the remainder of the response. Otherwise, we recommend that you iterate through the results field and do the following for each object in that list:</p>
-<ul>
-  <li>If <code>message_id</code> is set, check for <code>registration_id</code>:
-    <ul>
-      <li>If <code>registration_id</code> is set, replace the original ID with the new value (canonical ID) in your server database. Note that the original ID is not part of the result, so you need to obtain it from the list of <code>registration_ids</code> passed in the request (using the same index).</li>
-    </ul>
-  </li>
-  <li>Otherwise, get the value of <code>error</code>:
-    <ul>
-      <li>If it is <code>Unavailable</code>, you could retry to send it in another request.</li>
-      <li>If it is <code>NotRegistered</code>, you should remove the registration ID from your server database because the application was uninstalled from the device or it does not have a broadcast receiver configured to receive <code>com.google.android.c2dm.intent.RECEIVE</code> intents.</li>
-      <li>Otherwise, there is something wrong in the registration ID passed in the request; it is probably a non-recoverable error that will also require removing the registration from the server database. See <a href="#error_codes">Interpreting an error response</a> for all possible error values.</li>
-    </ul>
-  </li>
-</ul>
-
-<p>When a plain-text request is successful (HTTP status code 200), the response body contains 1 or 2 lines in the form of key/value pairs.
-The first line is always available and its content is either <code>id=<em>ID of sent message</em></code> or <code>Error=<em>GCM error code</em></code>. The second line, if available, 
-has the format of <code>registration_id=<em>canonical ID</em></code>. The second line is optional, and it can only be sent if the first line is not an error. We recommend handling the plain-text response in a similar way as handling the JSON response:</p>
-<ul>
-  <li>If first line starts with <code>id</code>, check second line:
-    <ul>
-      <li>If second line starts with <code>registration_id</code>, gets its value and replace the registration IDs in your server database.</li>
-    </ul>
-  </li>
-  <li>Otherwise, get the value of <code>Error</code>:
-    <ul>
-      <li>If it is <code>NotRegistered</code>, remove the registration ID from your server database.</li>
-      <li>Otherwise, there is probably a non-recoverable error (<strong>Note: </strong>Plain-text requests will never return <code>Unavailable</code> as the error code, they would have returned a 500 HTTP status instead).</li>
-    </ul>
-  </li>
-</ul>
-
-<h4 id="error_codes">Interpreting an error response</h4>
-<p>Here are the recommendations for handling the different types of error that might occur when trying to send a message to a device:</p>
-
-<dl>
-<dt id="missing_reg"><strong>Missing Registration ID</strong></dt>
-<dd>Check that the request contains a registration ID (either in the <code>registration_id</code> parameter in a plain text message, or in the <code>registration_ids</code> field in JSON). 
-<br/>Happens when error code is <code>MissingRegistration</code>.</dd>
-
-<dt id="invalid_reg"><strong>Invalid Registration ID</strong></dt>
-<dd>Check the formatting of the registration ID that you pass to the server. Make sure it matches the registration ID the phone receives in the <code>com.google.android.c2dm.intent.REGISTRATION</code> intent and that you're not truncating it or adding additional characters. 
-<br/>Happens when error code is <code>InvalidRegistration</code>.</dd>
-
-<dt id="mismatched_sender"><strong>Mismatched Sender</strong></dt>
-<dd>A registration ID is tied to a certain group of senders. When an application registers for GCM usage, it must specify which senders are allowed to send messages. Make sure you're using one of those when trying to send messages to the device. If you switch to a different sender, the existing registration IDs won't work. 
-Happens when error code is <code>MismatchSenderId</code>.</dd>
-
-<dt id="unreg_device"><strong>Unregistered Device</strong></dt>
-<dd>An existing registration ID may cease to be valid in a number of scenarios, including:
-<ul>
-  <li>If the application manually unregisters by issuing a <span class="prettyprint pretty-java"><code>com.google.android.c2dm.intent.UNREGISTER</code></span><code> </code>intent.</li>
-  <li>If the application is automatically unregistered, which can happen (but is not guaranteed) if the user uninstalls the application.</li>
-  <li>If the registration ID expires. Google might decide to refresh registration IDs. </li>
-  <li>If the application is updated but the new version does not have a broadcast receiver configured to receive <code>com.google.android.c2dm.intent.RECEIVE</code> intents.</li>
-</ul>
-For all these cases, you should remove this registration ID from the 3rd-party server and stop using it to send 
-messages. 
-<br/>Happens when error code is <code>NotRegistered</code>.</dd>
-
-<dt id="big_msg"><strong>Message Too Big</strong></dt>
-  <dd>The total size of the payload data that is included in a message can't exceed 4096 bytes. Note that this includes both the size of the keys as well as the values. 
-<br/>Happens when error code is <code>MessageTooBig</code>.</dd>
-
-<dt id="invalid_datakey"><strong>Invalid Data Key</strong></dt>
-<dd>The payload data contains a key (such as <code>from</code> or any value prefixed by <code>google.</code>) that is used internally by GCM in the  <code>com.google.android.c2dm.intent.RECEIVE</code> Intent and cannot be used. Note that some words (such as <code>collapse_key</code>) are also used by GCM but are allowed in the payload, in which case the payload value will be overridden by the GCM value. 
-<br />
-Happens when the error code is <code>InvalidDataKey</code>.</dd>
-
-<dt id="ttl_error"><strong>Invalid Time To Live</strong></dt>
-  <dd>The value for the Time to Live field must be an integer representing a duration in seconds between 0 and 2,419,200 (4 weeks). Happens when error code is <code>InvalidTtl</code>.
-</dd>
-
-  <dt id="auth_error"><strong>Authentication Error</strong></dt>
-  <dd>The sender account that you're trying to use to send a message couldn't be authenticated. Possible causes are: <ul>
-<li>Authorization header missing or with invalid syntax.</li>
-<li>Invalid project number sent as key.</li>
-<li>Key valid but with GCM service disabled.</li>
-<li>Request originated from a server not whitelisted in the Server Key IPs.</li>
-
-</ul>
-Check that the token you're sending inside the <code>Authorization</code> header is the correct API key associated with your project. You can check the validity of your API key by running the following command:<br/>
-
-<pre># api_key=YOUR_API_KEY
-
-# curl --header "Authorization: key=$api_key" --header Content-Type:"application/json" https://android.googleapis.com/gcm/send  -d "{\"registration_ids\":[\"ABC\"]}"</pre>
-
-
-
-If you receive a 401 HTTP status code, your API key is not valid. Otherwise you should see something like this:<br/>
-
-<pre>
-{"multicast_id":6782339717028231855,"success":0,"failure":1,"canonical_ids":0,"results":[{"error":"InvalidRegistration"}]}
-</pre>
-If you want to confirm the validity of a registration ID, you can do so by replacing "ABC" with the registration ID.
-<br/>
-Happens when the HTTP status code is 401.
-
-  <dt id="timeout"><strong>Timeout</strong></dt>
-
-<dd>The server couldn't process the request in time. You should retry the
-same request, but you MUST obey the following requirements:
-
-<ul>
-
-<li>Honor the <code>Retry-After</code> header if it's included in the response from the GCM server.</li>
-        
-        
-<li>Implement exponential back-off in your retry mechanism. This means an
-exponentially increasing delay after each failed retry (e.g. if you waited one
-second before the first retry, wait at least two second before the next one,
-then 4 seconds and so on). If you're sending multiple messages, delay each one
-independently by an additional random amount to avoid issuing a new request for
-all messages at the same time.</li>
-    
-
-Senders that cause problems risk being blacklisted. 
-<br />
-Happens when the HTTP status code is between 501 and 599, or when the <code>error</code> field of a JSON object in the results array is <code>Unavailable</code>.
-</dd>
-
-<dt id="internal_error"><strong>Internal Server Error</strong></dt>
-
-<dd>
-The server encountered an error while trying to process the request. You
-could retry the same request (obeying the requirements listed in the <a href="#timeout">Timeout</a>
-section), but if the error persists, please report the problem in the <a href="https://groups.google.com/forum/?fromgroups#!forum/android-gcm">android-gcm group</a>.
-<br />
-Happens when the HTTP status code is 500, or when the <code>error</code> field of a JSON
-object in the results array is <code>InternalServerError</code>.
-</dd>
-
-<dt id="restricted_package_name"><strong>Invalid Package Name</strong></dt>
-
-<dd>
-A message was addressed to a registration ID whose package name did not match the value passed in the request. Happens when error code is 
-<code>InvalidPackageName</code>.
-</dd>
-
-
-</dl>
-<h4>Example responses</h4>
-<p>This section shows a few examples of responses indicating messages that were processed successfully. See <a href="#example-requests">Example requests</a> for the requests these responses are based on.</p>
-<p> Here is a simple case of a JSON message successfully sent to one recipient without canonical IDs in the response:</p>
-<pre class="prettyprint pretty-json">{ "multicast_id": 108,
-  "success": 1,
-  "failure": 0,
-  "canonical_ids": 0,
-  "results": [
-    { "message_id": "1:08" }
-  ]
-}</pre>
-
-<p>Or if the request was in plain-text format:</p>
-<pre class="prettyprint">id=1:08
-</pre>
-
-<p>Here are JSON results for 6 recipients (IDs 4, 8, 15, 16, 23, and 42 respectively) with 3 messages successfully processed, 1 canonical registration ID returned, and 3 errors:</p>
-<pre class="prettyprint pretty-json">{ "multicast_id": 216,
-  "success": 3,
-  "failure": 3,
-  "canonical_ids": 1,
-  "results": [
-    { "message_id": "1:0408" },
-    { "error": "Unavailable" },
-    { "error": "InvalidRegistration" },
-    { "message_id": "1:1516" },
-    { "message_id": "1:2342", "registration_id": "32" },
-    { "error": "NotRegistered"}
-  ]
-}
-</pre>
-<p> In this example:</p>
-<ul>
-  <li>First message: success, not required.</li>
-  <li>Second message: should be resent (to registration ID 8).</li>
-  <li>Third message: had an unrecoverable error (maybe the value got corrupted in the database).</li>
-  <li>Fourth message: success, nothing required.</li>
-  <li>Fifth message: success, but the registration ID should be updated in the server database (from 23 to 32).</li>
-  <li>Sixth message: registration ID (42) should be removed from the server database because the application was uninstalled from the device.</li>
-</ul>
-<p>Or if just the 4th message above was sent using plain-text format:</p>
-<pre class="prettyprint">Error=InvalidRegistration
-</pre>
-<p>If the 5th message above was also sent using plain-text format:</p>
-<pre class="prettyprint">id=1:2342
-registration_id=32
-</pre>
-
-<h3 id="stats">Viewing Statistics</h3>
-
-<p>To view  statistics and any error messages for your GCM applications:</p>
-<ol>
-  <li> Go to the <code><a href="http://play.google.com/apps/publish">Developer Console</a></code>.</li>
-  <li>Login with your developer account. 
-  <p>You will see a page that has a list of all of your apps.</p></li>
-  <li> Click on the &quot;statistics&quot; link next to the app for which you want to view GCM stats. 
-  <p>Now you are on the statistics page.</p> </li>
-  <li>Go to the drop-down menu and select the GCM metric you want to view. 
-  </li>
-</ol>
-<p class="note"><strong>Note:</strong> Stats on the Google API Console are not enabled for GCM. You must use the <a href="http://play.google.com/apps/publish">Developer Console</a>.</p>
-
 
diff --git a/docs/html/google/gcm/gs.jd b/docs/html/google/gcm/gs.jd
index 8ceea0cc..f6b7ebe 100644
--- a/docs/html/google/gcm/gs.jd
+++ b/docs/html/google/gcm/gs.jd
@@ -1,4 +1,4 @@
-page.title=Getting Started with GCM
+page.title=Getting Started
 page.tags="cloud","push","messaging"
 @jd:body
 
@@ -12,8 +12,7 @@
 <li><a href="#create-proj">Creating a Google API Project</a></li>
 <li><a href="#gcm-service">Enabling the GCM Service</a></li>
 <li><a href="#access-key">Obtaining an API Key</a></li>
-<li><a href="#client">Writing a Client App</a></li>
-<li><a href="#server">Writing the Server Code</a></li>
+<li><a href="#next">Next Steps</a></li>
 </ol>
 
 <h2>See Also</h2>
@@ -26,12 +25,12 @@
 </div>
 </div>
 
-<p>The sections below guide you through the process of setting up a GCM
+<p>This document tells you how to get started setting up a GCM
 implementation.
-Before you start, make sure to <a href="/google/play-services/setup.html">set up
-the Google Play Services SDK</a>. You need this SDK to use the <a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">{@code GoogleCloudMessaging}</a> methods.</p>
-
-<p>Note that a full GCM implementation requires a server-side implementation, in addition to the client implementation in your app. This document offers a complete example that includes both the client and server.</p>
+Before you begin, make sure to <a href="/google/play-services/setup.html">set up
+the Google Play Services SDK</a>. You need this SDK to use the
+<a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">
+{@code GoogleCloudMessaging}</a> methods.</p>
 
 
 <h2 id="create-proj">Creating a Google API project</h2>
@@ -41,13 +40,17 @@
   </li>
   <li>If you haven't created an API project yet, this page will prompt you to do so:
   <p><img src="{@docRoot}images/gcm/gcm-create-api-proj.png" class="screenshot" /></p>
-<p class="note"><strong>Note:</strong> If you already have existing projects, the first page you see will be the <strong>Dashboard</strong> page. From there you can create a new project by opening the project drop-down menu (upper left corner) and choosing <strong>Other projects > Create</strong>.</p></li>
+<p class="note"><strong>Note:</strong> If you already have existing projects,
+the first page you see will be the <strong>Dashboard</strong> page. From there
+you can create a new project by opening the project drop-down menu (upper left corner)
+and choosing <strong>Other projects > Create</strong>.</p></li>
   <li> Click <strong>Create project</strong>.
     Your browser URL will change to something like:</li>
 
 <pre> https://code.google.com/apis/console/#project:<strong>4815162342</strong></pre>
 
-  <li> Take note of the value after <code>#project:</code> (4815162342 in this example). This is your project number, and it will be used later on as the GCM sender ID.</li>
+  <li> Take note of the value after <code>#project:</code> (4815162342 in this
+example). This is your project number, and it will be used later on as the GCM sender ID.</li>
   
 </ol>
 <h2 id="gcm-service">Enabling the GCM Service</h2>
@@ -61,463 +64,53 @@
 <h2 id="access-key">Obtaining an API Key</h2>
 <p>To obtain an API  key:</p>
 <ol>
-  <li> In the main Google APIs Console page, select <strong>API Access</strong>. You will see a screen that resembles the following:</li><br />
+  <li> In the main Google APIs Console page, select <strong>API Access</strong>.
+You will see a screen that resembles the following:</li>
 
 
-<img src="{@docRoot}images/gcm/gcm-api-access.png" style="width:400px;padding:4px;margin-bottom:0em;">
+<img src="{@docRoot}images/gcm/gcm-api-access.png" style="width:400px;padding:4px;">
+
+  <li>Click  <strong>Create new Server key</strong>. Either a server key or a
+browser key should work. The advantage to using a server key is that it allows
+you to whitelist IP addresses. The following screen appears:</li>
 
 
-  <li>Click  <strong>Create new Server key</strong>. Either a server key or a browser key should work. The advantage to using a server key is that it allows you to whitelist IP addresses. The following screen appears:</li><br />
-
-
-<img src="{@docRoot}images/gcm/gcm-config-server-key.png" style="width:400px;padding:4px;margin-bottom:0em;">
+<img src="{@docRoot}images/gcm/gcm-config-server-key.png" style="width:400px;padding:4px;">
 
   
-  <li>Click <strong>Create</strong>:</li><br />
+  <li>Click <strong>Create</strong>:</li>
   
 
-<img src="{@docRoot}images/gcm/gcm-api-key.png" style="width:400px;padding:4px;margin-bottom:0em;">
+<img src="{@docRoot}images/gcm/gcm-api-key.png" style="width:400px;padding:4px;">
 
 
 
 </ol>
-<p> Take note of the <strong>API key</strong> value (<code>YourKeyWillBeShownHere</code>) in this example, as it will be used later on.</p>
-<p class="note"><strong>Note:</strong> If you need to rotate the key, click  <strong>Generate new key</strong>. A new key  will be created while the old one will still be active for up to 24 hours. If you want to get rid of the old key immediately (for example, if you feel it was compromised), click <strong>Delete key</strong>.</p>
+<p> Take note of the <strong>API key</strong> value (<code>YourKeyWillBeShownHere</code>)
+in this example, as it will be used later on.</p>
+<p class="note"><strong>Note:</strong> If you need to rotate the key, click
+<strong>Generate new key</strong>. A new key  will be created while the old one
+will still be active for up to 24 hours. If you want to get rid of the old key
+immediately (for example, if you feel it was compromised), click <strong>Delete key</strong>.</p>
 
-<p>The following sections walk you through the steps of creating client and server-side code.</p>
+<h2 id="next">Next Steps</h2>
 
-<h2 id="client">Writing a Client App</h2>
+<p>Once you've finished the tasks listed above, you're ready to start
+implementing GCM. Here is an overview of the basic steps:</p>
 
-<p>This section walks you through the steps involved in writing a client-side application&mdash;that is, the GCM-enabled application that runs on an Android device. This client sample is designed to work in conjunction with the server code shown in <a href="#server">Writing the Server Code</a>, below.</p>
-
-
-
-<h3 id="manifest">Step 1: Edit Your App's Manifest</h3>
-<ul>
-  <li>The <code>com.google.android.c2dm.permission.RECEIVE</code> permission so the Android application can register and receive messages.</li>
-  <li>The <code>android.permission.INTERNET</code> permission so the Android application can send the registration ID to the 3rd party server.</li>
-  <li>The <code>android.permission.GET_ACCOUNTS</code> permission as GCM requires a Google account (necessary only if if the device is running a version lower than Android 4.0.4)</li>
-  <li>The <code>android.permission.WAKE_LOCK</code> permission so the application can keep the processor from sleeping when a message is received. Optional&mdash;use only if the app wants to keep the device from sleeping.</li>
-  <li>An <code>applicationPackage + &quot;.permission.C2D_MESSAGE&quot;</code> permission to prevent other Android applications from registering and receiving the Android application's
-messages. The permission name must exactly match this pattern&mdash;otherwise the Android application will not receive the messages.</li>
-   <li>A receiver for <code>com.google.android.c2dm.intent.RECEIVE</code>, with the category set
-as <code>applicationPackage</code>. The receiver should require the <code>com.google.android.c2dm.SEND</code> permission, so that only the GCM
-Framework can send a message to it. Note that the receiving
-of messages is implemented as an <a href="{@docRoot}guide/components/intents-filters.html">intent</a>.</li>
-  <li>An intent service to handle the intents received by the broadcast receiver. Optional.</li>
-  <li>If the GCM feature is critical to the Android application's function, be sure to
-set <code>android:minSdkVersion=&quot;8&quot;</code> in the manifest. This
-ensures that the Android application cannot be installed in an environment in which it
-could not run properly. </li>
-</ul>
-
-<p>Here are excerpts from a manifest that supports GCM:</p>
-
-<pre class="prettyprint pretty-xml">
-&lt;manifest package="com.example.gcm" ...&gt;
-
-    &lt;uses-sdk android:minSdkVersion="8" android:targetSdkVersion="17"/&gt;
-    &lt;uses-permission android:name="android.permission.INTERNET" /&gt;
-    &lt;uses-permission android:name="android.permission.GET_ACCOUNTS" /&gt;
-    &lt;uses-permission android:name="android.permission.WAKE_LOCK" /&gt;
-    &lt;uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" /&gt;
-
-    &lt;permission android:name="com.example.gcm.permission.C2D_MESSAGE" 
-        android:protectionLevel="signature" /&gt;
-    &lt;uses-permission android:name="com.example.gcm.permission.C2D_MESSAGE" /&gt;
-
-    &lt;application ...&gt;
-        &lt;receiver
-            android:name=".MyBroadcastReceiver"
-            android:permission="com.google.android.c2dm.permission.SEND" &gt;
-            &lt;intent-filter&gt;
-                &lt;action android:name="com.google.android.c2dm.intent.RECEIVE" /&gt;
-                &lt;category android:name="com.example.gcm" /&gt;
-            &lt;/intent-filter&gt;
-        &lt;/receiver&gt;
-        &lt;service android:name=".MyIntentService" /&gt;
-    &lt;/application&gt;
-
-&lt;/manifest&gt;
-</pre>
-
-
-<h3 id="register">Step 2: Register for GCM</h3>
-
-<p>An Android application running on a mobile device registers to receive messages by calling 
-the <a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">{@code GoogleCloudMessaging}</a> method 
-<a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html#register">{@code register(senderID...)}</a>.
-This method registers the application for GCM and returns the registration ID. This streamlined approach replaces the previous
-GCM registration process. See the example below for details.</p>
-
-<h3 id="app"> Step 3: Write Your Application</h3>
-
-<p>Finally, write your application. GCM offers a variety of ways to get the job done:</p>
-
-<ul>
-  <li>For your messaging server, you can either use the new <a href="ccs.html">GCM Cloud Connection Server</a> (CCS), the older <a href="gcm.html">GCM HTTP server</a>, or both in tandem. For more discussion, see see <a href="server.html">GCM Server</a>.</li>
-  <li>To write your client application (that is, the GCM-enabled app that runs on an Android device), use the <a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">{@code GoogleCloudMessaging}</a> APIs as shown below. Don't forget to set up your project to use the Google Play services SDK as described in <a href="/google/play-services/setup.html">Setup Google Play Services SDK</a>.</li>
-</ul>
-</li>
-  
-</ul>
-
-<h4 id="example">Example</h4>
-
-<p>Here is a sample client application that illustrates how to use the <a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">{@code GoogleCloudMessaging}</a> APIs. The sample consists of a main activity ({@code DemoActivity}) and a broadcast receiver ({@code GcmBroadcastReceiver}). You can use this client sample code in conjunction with the server code shown in <a href="#server">Writing the Server Code</a>.</p>
-
-<p>Note the following:</p>
-
-<ul>
-  <li>The sample primarily illustrates two things: registration, and upstream messaging. Upstream messaging only applies to apps that are running against a <a href="ccs.html">CCS</a> server; HTTP-based servers don't support upstream messaging.</li>
-  <li>The <a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">{@code GoogleCloudMessaging}</a> registration APIs replace the old registration process, which was based on the now-obsolete client helper library. While the old registration process still works, we encourage you to use the newer <a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">{@code GoogleCloudMessaging}</a> registration APIs, regardless of your underlying server.</li>
-</ul>
-
-<h5>Registering</h5>
-<p>An Android application needs to register with GCM servers before it can receive messages. So in its {@code onCreate()} method, {@code DemoActivity} checks to see whether the app is registered with GCM and with the server:</p>
-
-<pre>/**
- * Main UI for the demo app.
- */
-public class DemoActivity extends Activity {
-
-    public static final String EXTRA_MESSAGE = "message";
-    public static final String PROPERTY_REG_ID = "registration_id";
-    private static final String PROPERTY_APP_VERSION = "appVersion";
-    private static final String PROPERTY_ON_SERVER_EXPIRATION_TIME =
-            "onServerExpirationTimeMs";
-    /**
-     * Default lifespan (7 days) of a reservation until it is considered expired.
-     */
-    public static final long REGISTRATION_EXPIRY_TIME_MS = 1000 * 3600 * 24 * 7;
-
-    /**
-     * Substitute you own sender ID here.
-     */
-    String SENDER_ID = "Your-Sender-ID";
-
-    /**
-     * Tag used on log messages.
-     */
-    static final String TAG = "GCMDemo";
-
-    TextView mDisplay;
-    GoogleCloudMessaging gcm;
-    AtomicInteger msgId = new AtomicInteger();
-    SharedPreferences prefs;
-    Context context;
-
-    String regid;
-
-    &#64;Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        setContentView(R.layout.main);
-        mDisplay = (TextView) findViewById(R.id.display);
-
-        context = getApplicationContext();
-        regid = getRegistrationId(context);
-
-        if (regid.length() == 0) {
-            registerBackground();
-        }
-        gcm = GoogleCloudMessaging.getInstance(this);
-    }
-...
-}</pre>
-
-<p>The app calls {@code getRegistrationId()} to see whether there is an existing registration ID stored in shared preferences:</p>
-
-<pre>/**
- * Gets the current registration id for application on GCM service.
- * &lt;p&gt;
- * If result is empty, the registration has failed.
- *
- * &#64;return registration id, or empty string if the registration is not
- *         complete.
- */
-private String getRegistrationId(Context context) {
-    final SharedPreferences prefs = getGCMPreferences(context);
-    String registrationId = prefs.getString(PROPERTY_REG_ID, "");
-    if (registrationId.length() == 0) {
-        Log.v(TAG, "Registration not found.");
-        return "";
-    }
-    // check if app was updated; if so, it must clear registration id to
-    // avoid a race condition if GCM sends a message
-    int registeredVersion = prefs.getInt(PROPERTY_APP_VERSION, Integer.MIN_VALUE);
-    int currentVersion = getAppVersion(context);
-    if (registeredVersion != currentVersion || isRegistrationExpired()) {
-        Log.v(TAG, "App version changed or registration expired.");
-        return "";
-    }
-    return registrationId;
-}
-
-...
-
-/**
- * &#64;return Application's {&#64;code SharedPreferences}.
- */
-private SharedPreferences getGCMPreferences(Context context) {
-    return getSharedPreferences(DemoActivity.class.getSimpleName(), 
-            Context.MODE_PRIVATE);
-}</pre>
-
-<p>If the registration ID doesn't exist, or the app was updated, or the registration ID has expired, {@code getRegistrationId()} returns an empty string to indicate that the app needs to get a new regID. {@code getRegistrationId()} calls the following methods to check the app version and whether the regID has expired:</p>
-
-<pre>/**
- * &#64;return Application's version code from the {&#64;code PackageManager}.
- */
-private static int getAppVersion(Context context) {
-    try {
-        PackageInfo packageInfo = context.getPackageManager()
-                .getPackageInfo(context.getPackageName(), 0);
-        return packageInfo.versionCode;
-    } catch (NameNotFoundException e) {
-        // should never happen
-        throw new RuntimeException("Could not get package name: " + e);
-    }
-}
-
-/**
- * Checks if the registration has expired.
- *
- * &lt;p&gt;To avoid the scenario where the device sends the registration to the
- * server but the server loses it, the app developer may choose to re-register
- * after REGISTRATION_EXPIRY_TIME_MS.
- *
- * &#64;return true if the registration has expired.
- */
-private boolean isRegistrationExpired() {
-    final SharedPreferences prefs = getGCMPreferences(context);
-    // checks if the information is not stale
-    long expirationTime =
-            prefs.getLong(PROPERTY_ON_SERVER_EXPIRATION_TIME, -1);
-    return System.currentTimeMillis() > expirationTime;
-}</pre>
-
-
-<p>If there isn't a valid existing registration ID, {@code DemoActivity} calls the following {@code registerBackground()} method to register. Note that because GCM methods are blocking, this has to take place on a background thread. This sample uses {@link android.os.AsyncTask} to accomplish this:</p>
-
-<pre>
-/**
- * Registers the application with GCM servers asynchronously.
- * &lt;p&gt;
- * Stores the registration id, app versionCode, and expiration time in the 
- * application's shared preferences.
- */
-private void registerBackground() {
-    new AsyncTask<Void, Void, String>() {
-        &#64;Override
-        protected String doInBackground(Void... params) {
-            String msg = "";
-            try {
-                if (gcm == null) {
-                    gcm = GoogleCloudMessaging.getInstance(context);
-                }
-                regid = gcm.register(SENDER_ID);
-                msg = "Device registered, registration id=" + regid;
-
-                // You should send the registration ID to your server over HTTP,
-                // so it can use GCM/HTTP or CCS to send messages to your app.
-
-                // For this demo: we don't need to send it because the device
-                // will send upstream messages to a server that echo back the message
-                // using the 'from' address in the message.
-
-                // Save the regid - no need to register again.
-                setRegistrationId(context, regid);
-            } catch (IOException ex) {
-                msg = "Error :" + ex.getMessage();
-            }
-            return msg;
-        }
-
-        &#64;Override
-        protected void onPostExecute(String msg) {
-            mDisplay.append(msg + "\n");
-        }
-    }.execute(null, null, null);
-}</pre>
-
-<p>After registering, the app calls {@code setRegistrationId()} to store the registration ID in shared preferences for future use:</p>
-
-<pre>/**
- * Stores the registration id, app versionCode, and expiration time in the
- * application's {&#64;code SharedPreferences}.
- *
- * &#64;param context application's context.
- * &#64;param regId registration id
- */
-private void setRegistrationId(Context context, String regId) {
-    final SharedPreferences prefs = getGCMPreferences(context);
-    int appVersion = getAppVersion(context);
-    Log.v(TAG, "Saving regId on app version " + appVersion);
-    SharedPreferences.Editor editor = prefs.edit();
-    editor.putString(PROPERTY_REG_ID, regId);
-    editor.putInt(PROPERTY_APP_VERSION, appVersion);
-    long expirationTime = System.currentTimeMillis() + REGISTRATION_EXPIRY_TIME_MS;
-
-    Log.v(TAG, "Setting registration expiry time to " +
-            new Timestamp(expirationTime));
-    editor.putLong(PROPERTY_ON_SERVER_EXPIRATION_TIME, expirationTime);
-    editor.commit();
-}</pre>
-
-<h5>Sending a message</h5>
-<p>When the user clicks the app's <strong>Send</strong> button, the app sends an upstream message using the new <a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">{@code GoogleCloudMessaging}</a> APIs. In order to receive the upstream message, your server should be connected to CCS. You can use the code shown in <a href="#server">Writing the Server Code</a> as a sample XMPP client to connect to CCS.</p>
-
-<pre>public void onClick(final View view) {
-    if (view == findViewById(R.id.send)) {
-        new AsyncTask<Void, Void, String>() {
-            &#64;Override
-            protected String doInBackground(Void... params) {
-                String msg = "";
-                try {
-                    Bundle data = new Bundle();
-                    data.putString("hello", "World");
-                    String id = Integer.toString(msgId.incrementAndGet());
-                    gcm.send(SENDER_ID + "&#64;gcm.googleapis.com", id, data);
-                    msg = "Sent message";
-                } catch (IOException ex) {
-                    msg = "Error :" + ex.getMessage();
-                }
-                return msg;
-            }
-
-            &#64;Override
-            protected void onPostExecute(String msg) {
-                mDisplay.append(msg + "\n");
-            }
-        }.execute(null, null, null);
-    } else if (view == findViewById(R.id.clear)) {
-        mDisplay.setText("");
-    } 
-}</pre>
-
-<p>As described above in <a href="#manifest">Step 1</a>, the app includes a broadcast receiver for the <code>com.google.android.c2dm.intent.RECEIVE</code> intent. This is the mechanism GCM uses to deliver messages. When {@code onClick()} calls {@code gcm.send()}, it triggers the broadcast receiver's {@code onReceive()} method, which has the responsibility of handling the GCM message. In this sample the receiver's {@code onReceive()} method calls {@code sendNotification()} to put the message into a notification:</p>
-
-<pre>/**
- * Handling of GCM messages.
- */
-public class GcmBroadcastReceiver extends BroadcastReceiver {
-    static final String TAG = "GCMDemo";
-    public static final int NOTIFICATION_ID = 1;
-    private NotificationManager mNotificationManager;
-    NotificationCompat.Builder builder;
-    Context ctx;
-    &#64;Override
-    public void onReceive(Context context, Intent intent) {
-        GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(context);
-        ctx = context;
-        String messageType = gcm.getMessageType(intent);
-        if (GoogleCloudMessaging.MESSAGE_TYPE_SEND_ERROR.equals(messageType)) {
-            sendNotification("Send error: " + intent.getExtras().toString());
-        } else if (GoogleCloudMessaging.MESSAGE_TYPE_DELETED.equals(messageType)) {
-            sendNotification("Deleted messages on server: " +
-                    intent.getExtras().toString());
-        } else {
-            sendNotification("Received: " + intent.getExtras().toString());
-        }
-        setResultCode(Activity.RESULT_OK);
-    }
-
-    // Put the GCM message into a notification and post it.
-    private void sendNotification(String msg) {
-        mNotificationManager = (NotificationManager)
-                ctx.getSystemService(Context.NOTIFICATION_SERVICE);
-
-        PendingIntent contentIntent = PendingIntent.getActivity(ctx, 0,
-                new Intent(ctx, DemoActivity.class), 0);
-
-        NotificationCompat.Builder mBuilder =
-                new NotificationCompat.Builder(ctx)
-        .setSmallIcon(R.drawable.ic_stat_gcm)
-        .setContentTitle("GCM Notification")
-        .setStyle(new NotificationCompat.BigTextStyle()
-        .bigText(msg))
-        .setContentText(msg);
-
-        mBuilder.setContentIntent(contentIntent);
-        mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
-    }
-}</pre>
-
-<h2 id="server">Writing the Server Code</h2>
-
-<p>Here is an example of a CCS server written in Python. You can use this in conjunction with the sample client code shown above. This sample echo server sends an initial message, and for every upstream message received, it sends a dummy response back to the application that sent the upstream message. This example illustrates how to connect,
-send, and receive GCM messages using XMPP. It shouldn't be used as-is
-on a production deployment. For examples of HTTP-based servers, see <a href="server.html">GCM Server</a>.</p>
-
-<pre>
-#!/usr/bin/python
-import sys, json, xmpp, random, string
-
-SERVER = 'gcm.googleapis.com'
-PORT = 5235
-USERNAME = ''
-PASSWORD = ''
-REGISTRATION_ID = ''
-
-unacked_messages_quota = 1000
-send_queue = []
-
-# Return a random alphanumerical id
-def random_id():
-  rid = ''
-  for x in range(8): rid += random.choice(string.ascii_letters + string.digits)
-  return rid
-
-def message_callback(session, message):
-  global unacked_messages_quota
-  gcm = message.getTags('gcm')
-  if gcm:
-    gcm_json = gcm[0].getData()
-    msg = json.loads(gcm_json)
-    if not msg.has_key('message_type'):
-      # Acknowledge the incoming message immediately.
-      send({'to': msg['from'],
-            'message_type': 'ack',
-            'message_id': msg['message_id']})
-      # Queue a response back to the server.
-      if msg.has_key('from'):
-        # Send a dummy echo response back to the app that sent the upstream message.
-        send_queue.append({'to': msg['from'],
-                           'message_id': random_id(),
-                           'data': {'pong': 1}})
-    elif msg['message_type'] == 'ack' or msg['message_type'] == 'nack':
-      unacked_messages_quota += 1
-
-def send(json_dict):
-  template = (&quot;&lt;message&gt;&lt;gcm xmlns='google:mobile:data'&gt;{1}&lt;/gcm&gt;&lt;/message&gt;&quot;)
-  client.send(xmpp.protocol.Message(
-      node=template.format(client.Bind.bound[0], json.dumps(json_dict))))
-
-def flush_queued_messages():
-  global unacked_messages_quota
-  while len(send_queue) and unacked_messages_quota &gt; 0:
-    send(send_queue.pop(0))
-    unacked_messages_quota -= 1
-
-client = xmpp.Client('gcm.googleapis.com', debug=['socket'])
-client.connect(server=(SERVER,PORT), secure=1, use_srv=False)
-auth = client.auth(USERNAME, PASSWORD)
-if not auth:
-  print 'Authentication failed!'
-  sys.exit(1)
-
-client.RegisterHandler('message', message_callback)
-
-send_queue.append({'to': REGISTRATION_ID,
-                   'message_id': 'reg_id',
-                   'data': {'message_destination': 'RegId',
-                            'message_id': random_id()}})
-
-while True:
-  client.Process(1)
-  flush_queued_messages()</pre>
-
+<ol>
+  <li>Decide which Google-provided GCM connection server you want to use&mdash;
+  <a href="http.html">HTTP</a> or <a href="ccs.html">XMPP</a> (CCS). GCM connection servers
+take messages from a 3rd-party application
+server (written by you) and send them to a GCM-enabled Android application (the
+"client app," also written by you) running on a device. </li>
+  <li>Implement an application server (the "3rd-party application server") to interact
+with your chosen GCM connection server. The app server sends data to a
+GCM-enabled Android client application via the GCM connection server. For more
+information about implementing the server side, see <a href="server.html">
+Implementing GCM Server</a>.</li>
+<li>Write your client app. This is the GCM-enabled Android application that runs
+on a device. See <a href="client.html">Implementing GCM Client</a> for more information.</li>
+</ol>
 
 
diff --git a/docs/html/google/gcm/http.jd b/docs/html/google/gcm/http.jd
new file mode 100644
index 0000000..b8d8659
--- /dev/null
+++ b/docs/html/google/gcm/http.jd
@@ -0,0 +1,618 @@
+page.title=GCM HTTP Connection Server
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+
+
+<h2>In this document</h2>
+
+<ol class="toc">
+  <li><a href="#auth">Authentication</a> </li>
+  <li><a href="#request">Request Format</a> </li>
+  <li><a href="#response">Response Format</a>
+  <ol class="toc">
+    <li><a href="#success">Interpreting a success response</a>
+    <li><a href="#error_codes">Interpreting an error response</a>
+    <li><a href="#example-responses">Example responses</a>
+  </ol>
+  </li>
+  <li><a href="#app-server">Implementing an HTTP-Based App Server</a>
+</ol>
+
+<h2>See Also</h2>
+
+<ol class="toc">
+<li><a href="gs.html">Getting Started</a></li>
+<li><a href="client.html">Implementing GCM Client</a></li>
+<li><a href="ccs.html">Cloud Connection Server</a></li>
+
+
+</ol>
+
+</div>
+</div>
+
+<p>This document describes the GCM HTTP connection server. Connection servers
+are the Google-provided servers that take messages from the 3rd-party
+application server and sending them to the device.</p>
+
+
+
+<p class="note"><strong>Note:</strong> See
+<a href="server.html#params">Implementing GCM Server</a> for a list of all the message
+parameters and which connection server(s) supports them.</p>
+
+
+<h2 id="auth">Authentication</h2>
+
+<p>To send a  message, the application server issues a POST request to
+<code>https://android.googleapis.com/gcm/send</code>.</p>
+<p>A  message request is made of 2 parts: HTTP header and HTTP body.</p>
+
+<p>The HTTP header must contain the following headers:</p>
+<ul>
+  <li><code>Authorization</code>: key=YOUR_API_KEY</li>
+  <li><code>Content-Type</code>: <code>application/json</code> for JSON; <code>application/x-www-form-urlencoded;charset=UTF-8</code> for plain text.
+  </li>
+</ul>
+
+<p>For example:
+</p>
+<pre>Content-Type:application/json
+Authorization:key=AIzaSyB-1uEai2WiUapxCs2Q0GZYzPu7Udno5aA
+
+{
+  "registration_ids" : ["APA91bHun4MxP5egoKMwt2KZFBaFUH-1RYqx..."],
+  "data" : {
+    ...
+  },
+}</pre>
+<p class="note">
+  <p><strong>Note:</strong> If <code>Content-Type</code> is omitted, the format
+is assumed to be plain text.</p>
+</p>
+
+<p>The HTTP body content depends on whether you're using JSON or plain text.
+See
+<a href="server.html#params">Implementing GCM Server</a> for a list of all the
+parameters your JSON or plain text message can contain.</p>
+
+
+  <h2 id="request">Request Format</h2>
+  <p>Here is the smallest possible request (a message without any parameters and
+just one recipient) using JSON:</p>
+  <pre class="prettyprint pretty-json">{ &quot;registration_ids&quot;: [ &quot;42&quot; ] }</pre>
+
+  <p>And here the same example using plain text:</p>
+  <pre class="prettyprint">registration_id=42</pre>
+
+  <p> Here is a message with a payload and 6 recipients:</p>
+  <pre class="prettyprint pretty-HTML">{ "data": {
+    "score": "5x1",
+    "time": "15:10"
+  },
+  "registration_ids": ["4", "8", "15", "16", "23", "42"]
+}</pre>
+  <p>Here is a message with all optional fields set and 6 recipients:</p>
+  <pre class="prettyprint pretty-json">{ "collapse_key": "score_update",
+  "time_to_live": 108,
+  "delay_while_idle": true,
+  "data": {
+    "score": "4x8",
+    "time": "15:16.2342"
+  },
+  "registration_ids":["4", "8", "15", "16", "23", "42"]
+}</pre>
+  <p>And here is the same message using plain-text format (but just 1 recipient):  </p>
+
+  <pre class="prettyprint">collapse_key=score_update&amp;time_to_live=108&amp;delay_while_idle=1&amp;data.score=4x8&amp;data.time=15:16.2342&amp;registration_id=42
+  </pre>
+
+<p class="note"><strong>Note:</strong> If your organization has a firewall
+that restricts the traffic to or
+from the Internet, you need to configure it to allow connectivity with GCM in order for
+your Android devices to receive messages.
+The ports to open are: 5228, 5229, and 5230. GCM typically only uses 5228, but
+it sometimes uses 5229 and 5230. GCM doesn't provide specific IPs, so you should allow
+your firewall to accept outgoing connections to all IP addresses
+contained in the IP blocks listed in Google's ASN of 15169.</p>
+
+
+
+<h2 id="response">Response format</h2>
+
+<p>There are two possible outcomes when trying to send a message:</p>
+<ul>
+  <li>The message is processed successfully.</li>
+  <li>The GCM server rejects the request.</li>
+</ul>
+
+<p>When the message is processed successfully, the HTTP response has a 200 status
+and the body contains more information about the status of the message
+(including possible errors). When the request is rejected,
+the HTTP response contains a non-200 status code (such as 400, 401, or 503).</p>
+
+<p>The following table summarizes the statuses that the HTTP response header might
+contain. Click the troubleshoot link for advice on how to deal with each type of
+error.</p>
+<table border=1>
+  <tr>
+    <th>Response</th>
+    <th>Description</th>
+  </tr>
+  <tr>
+    <td>200</td>
+    <td>Message was processed successfully. The response body will contain more
+details about the message status, but its format will depend whether the request
+was JSON or plain text. See <a href="#success">Interpreting a success response</a>
+for more details.</td>
+  </tr>
+  <tr>
+    <td>400</td>
+    <td><span id="internal-source-marker_0.2">Only applies for JSON requests.
+Indicates that the request could not be parsed as JSON, or it contained invalid
+fields (for instance, passing a string where a number was expected). The exact
+failure reason is described in the response and the problem should be addressed
+before the request can be retried.</td>
+  </tr>
+  <tr>
+    <td>401</td>
+    <td>There was an error authenticating the sender account.
+<a href="#auth_error">Troubleshoot</a></td>
+  </tr>
+  <tr>
+    <td>5xx</td>
+    <td>Errors in the 500-599 range (such as 500 or 503) indicate that there wa
+an internal error in the GCM server while trying to process the request, or that
+the server is temporarily unavailable (for example, because of timeouts). Sender
+must retry later, honoring any <code>Retry-After</code> header included in the
+response. Application servers must implement exponential back-off.
+<a href="#internal_error">Troubleshoot</a></td>
+  </tr>
+</table>
+
+<h3 id="success">Interpreting a success response</h3>
+<p>When a JSON request is successful (HTTP status code 200), the response body
+contains a JSON object with the following fields:</p>
+<table>
+  <tr>
+    <th>Field</th>
+    <th>Description</th>
+  </tr>
+  <tr>
+    <td><code>multicast_id</code></td>
+    <td>Unique ID (number) identifying the multicast message.</td>
+  </tr>
+  <tr>
+    <td><code>success</code></td>
+    <td>Number of messages that were processed without an error.</td>
+  </tr>
+  <tr>
+    <td><code>failure</code></td>
+    <td>Number of messages that could not be processed.</td>
+  </tr>
+  <tr>
+    <td><code>canonical_ids</code></td>
+    <td>Number of results that contain a canonical registration ID. See
+<a href="adv.html#canonical">Advanced Topics</a> for more discussion of this topic.</td>
+  </tr>
+  <tr>
+    <td><code>results</code></td>
+    <td>Array of objects representing the status of the messages processed. The
+objects are listed in the same order as the request (i.e., for each registration
+ID in the request, its result is listed in the same index in the response) and
+they can have these fields:<br>
+      <ul>
+        <li><code>message_id</code>: String representing the message when it was
+successfully processed.</li>
+        <li><code>registration_id</code>: If set,  means that GCM processed the
+message but it has another canonical registration ID for that device, so sender
+should replace the IDs on future requests (otherwise they might be rejected).
+This field is never set if there is an error in the request.
+        </li>
+        <li><code>error</code>: String describing an error that occurred while
+processing the message for that recipient. The possible values are the same as
+documented in the above table, plus &quot;Unavailable&quot;  (meaning GCM servers
+were busy and could not process the message for that  particular recipient, so
+it could be retried).</li>
+    </ul></td>
+  </tr>
+</table>
+<p>If the value of <code>failure</code> and <code>canonical_ids</code> is 0, it's
+not necessary to parse the remainder of the response. Otherwise, we recommend
+that you iterate through the results field and do the following for each object
+in that list:</p>
+<ul>
+  <li>If <code>message_id</code> is set, check for <code>registration_id</code>:
+    <ul>
+      <li>If <code>registration_id</code> is set, replace the original ID with
+the new value (canonical ID) in your server database. Note that the original ID
+is not part of the result, so you need to obtain it from the list of
+code>registration_ids</code> passed in the request (using the same index).</li>
+    </ul>
+  </li>
+  <li>Otherwise, get the value of <code>error</code>:
+    <ul>
+      <li>If it is <code>Unavailable</code>, you could retry to send it in another
+request.</li>
+      <li>If it is <code>NotRegistered</code>, you should remove the registration
+ID from your server database because the application was uninstalled from the
+device or it does not have a broadcast receiver configured to receive
+<code>com.google.android.c2dm.intent.RECEIVE</code> intents.</li>
+      <li>Otherwise, there is something wrong in the registration ID passed in
+the request; it is probably a non-recoverable error that will also require removing
+the registration from the server database. See <a href="#error_codes">Interpreting
+an error response</a> for all possible error values.</li>
+    </ul>
+  </li>
+</ul>
+
+<p>When a plain-text request is successful (HTTP status code 200), the response
+body contains 1 or 2 lines in the form of key/value pairs.
+The first line is always available and its content is either <code>id=<em>ID of
+sent message</em></code> or <code>Error=<em>GCM error code</em></code>. The second
+line, if available,
+has the format of <code>registration_id=<em>canonical ID</em></code>. The second
+line is optional, and it can only be sent if the first line is not an error. We
+recommend handling the plain-text response in a similar way as handling the
+JSON response:</p>
+<ul>
+  <li>If first line starts with <code>id</code>, check second line:
+    <ul>
+      <li>If second line starts with <code>registration_id</code>, gets its value
+and replace the registration IDs in your server database.</li>
+    </ul>
+  </li>
+  <li>Otherwise, get the value of <code>Error</code>:
+    <ul>
+      <li>If it is <code>NotRegistered</code>, remove the registration ID from
+your server database.</li>
+      <li>Otherwise, there is probably a non-recoverable error (<strong>Note:
+</strong>Plain-text requests will never return <code>Unavailable</code> as the
+error code, they would have returned a 500 HTTP status instead).</li>
+    </ul>
+  </li>
+</ul>
+
+<h3 id="error_codes">Interpreting an error response</h3>
+<p>Here are the recommendations for handling the different types of error that
+might occur when trying to send a message to a device:</p>
+
+<dl>
+<dt id="missing_reg"><strong>Missing Registration ID</strong></dt>
+<dd>Check that the request contains a registration ID (either in the
+<code>registration_id</code> parameter in a plain text message, or in the
+<code>registration_ids</code> field in JSON).
+<br/>Happens when error code is <code>MissingRegistration</code>.</dd>
+
+<dt id="invalid_reg"><strong>Invalid Registration ID</strong></dt>
+<dd>Check the formatting of the registration ID that you pass to the server. Make
+sure it matches the registration ID the phone receives in the
+<code>com.google.android.c2dm.intent.REGISTRATION</code> intent and that you're
+not truncating it or adding additional characters.
+<br/>Happens when error code is <code>InvalidRegistration</code>.</dd>
+
+<dt id="mismatched_sender"><strong>Mismatched Sender</strong></dt>
+<dd>A registration ID is tied to a certain group of senders. When an application
+registers for GCM usage, it must specify which senders are allowed to send messages.
+Make sure you're using one of those when trying to send messages to the device.
+If you switch to a different sender, the existing registration IDs won't work.
+Happens when error code is <code>MismatchSenderId</code>.</dd>
+
+<dt id="unreg_device"><strong>Unregistered Device</strong></dt>
+<dd>An existing registration ID may cease to be valid in a number of scenarios, including:
+<ul>
+  <li>If the application manually unregisters by issuing a
+<span class="prettyprint pretty-java">
+<code>com.google.android.c2dm.intent.UNREGISTER</code></span><code>
+</code>intent.</li>
+  <li>If the application is automatically unregistered, which can happen
+(but is not guaranteed) if the user uninstalls the application.</li>
+  <li>If the registration ID expires. Google might decide to refresh registration
+IDs. </li>
+  <li>If the application is updated but the new version does not have a broadcast
+receiver configured to receive <code>com.google.android.c2dm.intent.RECEIVE</code>
+intents.</li>
+</ul>
+For all these cases, you should remove this registration ID from the 3rd-party
+server and stop using it to send
+messages.
+<br/>Happens when error code is <code>NotRegistered</code>.</dd>
+
+<dt id="big_msg"><strong>Message Too Big</strong></dt>
+  <dd>The total size of the payload data that is included in a message can't
+exceed 4096 bytes. Note that this includes both the size of the keys as well
+as the values.
+<br/>Happens when error code is <code>MessageTooBig</code>.</dd>
+
+<dt id="invalid_datakey"><strong>Invalid Data Key</strong></dt>
+<dd>The payload data contains a key (such as <code>from</code> or any value
+prefixed by <code>google.</code>) that is used internally by GCM in the
+<code>com.google.android.c2dm.intent.RECEIVE</code> Intent and cannot be used.
+Note that some words (such as <code>collapse_key</code>) are also used by GCM
+but are allowed in the payload, in which case the payload value will be
+overridden by the GCM value.
+<br />
+Happens when the error code is <code>InvalidDataKey</code>.</dd>
+
+<dt id="ttl_error"><strong>Invalid Time To Live</strong></dt>
+  <dd>The value for the Time to Live field must be an integer representing
+a duration in seconds between 0 and 2,419,200 (4 weeks). Happens when error code
+is <code>InvalidTtl</code>.
+</dd>
+
+  <dt id="auth_error"><strong>Authentication Error</strong></dt>
+  <dd>The sender account that you're trying to use to send a message couldn't be
+authenticated. Possible causes are: <ul>
+<li>Authorization header missing or with invalid syntax.</li>
+<li>Invalid project number sent as key.</li>
+<li>Key valid but with GCM service disabled.</li>
+<li>Request originated from a server not whitelisted in the Server Key IPs.</li>
+
+</ul>
+Check that the token you're sending inside the <code>Authorization</code> header
+is the correct API key associated with your project. You can check the validity
+of your API key by running the following command:<br/>
+
+<pre># api_key=YOUR_API_KEY
+
+# curl --header "Authorization: key=$api_key" --header Content-Type:"application/json" https://android.googleapis.com/gcm/send  -d "{\"registration_ids\":[\"ABC\"]}"</pre>
+
+
+
+If you receive a 401 HTTP status code, your API key is not valid. Otherwise you
+should see something like this:<br/>
+
+<pre>
+{"multicast_id":6782339717028231855,"success":0,"failure":1,"canonical_ids":0,"results":[{"error":"InvalidRegistration"}]}
+</pre>
+If you want to confirm the validity of a registration ID, you can do so by
+replacing "ABC" with the registration ID.
+<br/>
+Happens when the HTTP status code is 401.
+
+  <dt id="timeout"><strong>Timeout</strong></dt>
+
+<dd>The server couldn't process the request in time. You should retry the
+same request, but you MUST obey the following requirements:
+
+<ul>
+
+<li>Honor the <code>Retry-After</code> header if it's included in the response
+from the GCM server.</li>
+
+
+<li>Implement exponential back-off in your retry mechanism. This means an
+exponentially increasing delay after each failed retry (e.g. if you waited one
+second before the first retry, wait at least two second before the next one,
+then 4 seconds and so on). If you're sending multiple messages, delay each one
+independently by an additional random amount to avoid issuing a new request for
+all messages at the same time.</li>
+
+
+Senders that cause problems risk being blacklisted.
+<br />
+Happens when the HTTP status code is between 501 and 599, or when the
+<code>error</code> field of a JSON object in the results array is <code>Unavailable</code>.
+</dd>
+
+<dt id="internal_error"><strong>Internal Server Error</strong></dt>
+
+<dd>
+The server encountered an error while trying to process the request. You
+could retry the same request (obeying the requirements listed in the <a href="#timeout">Timeout</a>
+section), but if the error persists, please report the problem in the
+<a href="https://groups.google.com/forum/?fromgroups#!forum/android-gcm">android-gcm group</a>.
+<br />
+Happens when the HTTP status code is 500, or when the <code>error</code> field of a JSON
+object in the results array is <code>InternalServerError</code>.
+</dd>
+
+<dt id="restricted_package_name"><strong>Invalid Package Name</strong></dt>
+
+<dd>
+A message was addressed to a registration ID whose package name did not match
+the value passed in the request. Happens when error code is
+<code>InvalidPackageName</code>.
+</dd>
+</dl>
+
+<h3 id="example-responses">Example responses</h3>
+<p>This section shows a few examples of responses indicating messages that were
+processed successfully. See <a href="#request">Request Format</a> for
+the requests these responses are based on.</p>
+<p> Here is a simple case of a JSON message successfully sent to one recipient
+without canonical IDs in the response:</p>
+<pre class="prettyprint pretty-json">{ "multicast_id": 108,
+  "success": 1,
+  "failure": 0,
+  "canonical_ids": 0,
+  "results": [
+    { "message_id": "1:08" }
+  ]
+}</pre>
+
+<p>Or if the request was in plain-text format:</p>
+<pre class="prettyprint">id=1:08
+</pre>
+
+<p>Here are JSON results for 6 recipients (IDs 4, 8, 15, 16, 23, and 42 respectively)
+with 3 messages successfully processed, 1 canonical registration ID returned,
+and 3 errors:</p>
+<pre class="prettyprint pretty-json">{ "multicast_id": 216,
+  "success": 3,
+  "failure": 3,
+  "canonical_ids": 1,
+  "results": [
+    { "message_id": "1:0408" },
+    { "error": "Unavailable" },
+    { "error": "InvalidRegistration" },
+    { "message_id": "1:1516" },
+    { "message_id": "1:2342", "registration_id": "32" },
+    { "error": "NotRegistered"}
+  ]
+}
+</pre>
+<p> In this example:</p>
+<ul>
+  <li>First message: success, not required.</li>
+  <li>Second message: should be resent (to registration ID 8).</li>
+  <li>Third message: had an unrecoverable error (maybe the value got corrupted
+in the database).</li>
+  <li>Fourth message: success, nothing required.</li>
+  <li>Fifth message: success, but the registration ID should be updated in the
+server database (from 23 to 32).</li>
+  <li>Sixth message: registration ID (42) should be removed from the server database
+because the application was uninstalled from the device.</li>
+</ul>
+<p>Or if just the 4th message above was sent using plain-text format:</p>
+<pre class="prettyprint">Error=InvalidRegistration
+</pre>
+<p>If the 5th message above was also sent using plain-text format:</p>
+<pre class="prettyprint">id=1:2342
+registration_id=32
+</pre>
+
+
+<h2 id="app-server">Implementing an HTTP-Based App Server</h2>
+
+<p>This section gives examples of implementing an app server that works with the
+GCM HTTP connection server. Note that a full GCM implementation requires a
+client-side implementation, in addition to the server.</a>
+
+
+<p>Requirements</p>
+<p>For the web server:</p>
+<ul>
+  <li> <a href="http://ant.apache.org/">Ant 1.8</a> (it might work with earlier versions, but it's not guaranteed).</li>
+  <li>One of the following:
+    <ul>
+      <li>A running web server compatible with Servlets API version 2.5, such as
+<a href="http://tomcat.apache.org/">Tomcat 6</a> or <a href="http://jetty.codehaus.org/">Jetty</a>, or</li>
+      <li><a href="http://code.google.com/appengine/">Java App Engine SDK</a>
+version 1.6 or later.</li>
+    </ul>
+  </li>
+  <li>A Google account registered to use GCM.</li>
+  <li>The API  key for that account.</li>
+</ul>
+<p>For the Android application:</p>
+<ul>
+  <li>Emulator (or device) running Android 2.2 with Google APIs.</li>
+  <li>The Google API project number of the account registered to use GCM.</li>
+</ul>
+
+<h3 id="gcm-setup">Setting Up GCM</h3>
+<p>Before proceeding with the server and client setup, it's necessary to register
+a Google account with the Google API Console, enable Google Cloud Messaging in GCM,
+and obtain an API key from the <a href="https://code.google.com/apis/console">
+Google API Console</a>.</p>
+<p>For instructions on how to set up GCM, see <a href="gs.html">Getting Started</a>.</p>
+
+
+<h3 id="server-setup">Setting Up an HTTP Server</h3>
+<p>This section describes the different options for setting up an HTTP server.</p>
+
+<h4 id="webserver-setup">Using a standard web server</h4>
+<p>To set up the server using a standard, servlet-compliant web server:</p>
+<ol>
+  <li>From the <a href="http://code.google.com/p/gcm">open source site</a>,
+download the following directories: <code>gcm-server</code>,
+<code>samples/gcm-demo-server</code>, and <code>samples/gcm-demo-appengine</code>.</p>
+
+
+  <li>In a text editor, edit the <code>samples/gcm-demo-server/WebContent/WEB-INF/classes/api.key</code> and replace the existing text with the API key obtained above.</li>
+  <li>In a shell window, go to the <code>samples/gcm-demo-server</code> directory.</li>
+  <li>Generate the server's WAR file by running <code>ant war</code>:</li>
+
+  <pre class="prettyprint">$ ant war
+
+Buildfile:build.xml
+
+init:
+   [mkdir] Created dir: build/classes
+   [mkdir] Created dir: dist
+
+compile:
+   [javac] Compiling 6 source files to build/classes
+
+war:
+     [war] Building war: <strong>dist/gcm-demo.war</strong>
+
+BUILD SUCCESSFUL
+Total time: 0 seconds
+</pre>
+
+  <li>Deploy the <code>dist/gcm-demo.war</code> to your running server. For instance, if you're using Jetty, copy <code>gcm-demo.war</code> to the <code>webapps</code> directory of the Jetty installation.</li>
+  <li>Open the server's main page in a browser. The URL depends on the server you're using and your machine's IP address, but it will be something like <code>http://192.168.1.10:8080/gcm-demo/home</code>, where <code>gcm-demo</code> is the application context and <code>/home</code> is the path of the main servlet.
+
+  </li>
+</ol>
+<p class="note"><strong>Note:</strong> You can get the IP by running <code>ifconfig</code> on Linux or MacOS, or <code>ipconfig</code> on Windows. </p>
+
+<p> You server is now ready.</p>
+
+<h4 id="appengine-setup">Using App Engine for Java</h4>
+
+<p>To set up the server using a standard App Engine for Java:</p>
+<ol>
+  <li>Get the files from the <a href="http://code.google.com/p/gcm">open source
+site</a>, as described above.</p>
+  </li>
+  <li>In a text editor, edit
+<code>samples/gcm-demo-appengine/src/com/google/android/gcm/demo/server/ApiKeyInitializer.java</code>
+and replace the existing text with the API key obtained above.
+
+  <p class="note"><strong>Note:</strong> The API key value set in that class will
+be used just once to create a persistent entity on App Engine. If you deploy
+the application, you can use App Engine's <code>Datastore Viewer</code> to change
+it later.</p>
+
+  </li>
+  <li>In a shell window, go to the <code>samples/gcm-demo-appengine</code> directory.</li>
+  <li>Start the development App Engine server by <code>ant runserver</code>,
+using the <code>-Dsdk.dir</code> to indicate the location of the App Engine SDK
+and <code>-Dserver.host</code> to set your server's hostname or IP address:</li>
+
+<pre class="prettyprint">
+$ ant -Dsdk.dir=/opt/google/appengine-java-sdk runserver -Dserver.host=192.168.1.10
+Buildfile: gcm-demo-appengine/build.xml
+
+init:
+    [mkdir] Created dir: gcm-demo-appengine/dist
+
+copyjars:
+
+compile:
+
+datanucleusenhance:
+  [enhance] DataNucleus Enhancer (version 1.1.4) : Enhancement of classes
+  [enhance] DataNucleus Enhancer completed with success for 0 classes. Timings : input=28 ms, enhance=0 ms, total=28 ms. Consult the log for full details
+  [enhance] DataNucleus Enhancer completed and no classes were enhanced. Consult the log for full details
+
+runserver:
+     [java] Jun 15, 2012 8:46:06 PM com.google.apphosting.utils.jetty.JettyLogger info
+     [java] INFO: Logging to JettyLogger(null) via com.google.apphosting.utils.jetty.JettyLogger
+     [java] Jun 15, 2012 8:46:06 PM com.google.apphosting.utils.config.AppEngineWebXmlReader readAppEngineWebXml
+     [java] INFO: Successfully processed gcm-demo-appengine/WebContent/WEB-INF/appengine-web.xml
+     [java] Jun 15, 2012 8:46:06 PM com.google.apphosting.utils.config.AbstractConfigXmlReader readConfigXml
+     [java] INFO: Successfully processed gcm-demo-appengine/WebContent/WEB-INF/web.xml
+     [java] Jun 15, 2012 8:46:09 PM com.google.android.gcm.demo.server.ApiKeyInitializer contextInitialized
+     [java] SEVERE: Created fake key. Please go to App Engine admin console, change its value to your API Key (the entity type is 'Settings' and its field to be changed is 'ApiKey'), then restart the server!
+     [java] Jun 15, 2012 8:46:09 PM com.google.appengine.tools.development.DevAppServerImpl start
+     [java] INFO: The server is running at http://192.168.1.10:8080/
+     [java] Jun 15, 2012 8:46:09 PM com.google.appengine.tools.development.DevAppServerImpl start
+     [java] INFO: The admin console is running at http://192.168.1.10:8080/_ah/admin
+</pre>
+
+  <li>Open the server's main page in a browser. The URL depends on the server
+you're using and your machine's IP address, but it will be something like
+<code>http://192.168.1.10:8080/home</code>, where <code>/home</code>
+is the path of the main servlet.</li>
+
+  <p class="note"><strong>Note:</strong> You can get the IP by running <code>ifconfig</code>
+on Linux or MacOS, or <code>ipconfig</code> on Windows.</p>
+
+</ol>
+<p> You server is now ready.</p>
diff --git a/docs/html/google/gcm/notifications.jd b/docs/html/google/gcm/notifications.jd
index 5171850..43a7368 100644
--- a/docs/html/google/gcm/notifications.jd
+++ b/docs/html/google/gcm/notifications.jd
@@ -14,14 +14,15 @@
 <h2>In this document</h2>
 
 <ol class="toc">
-  <li><a href="#what">What are User Notifications?</a> </li>
-  <li><a href="#examples">Examples</a>
-    <ol>
-      <li><a href="#create">Generate a notification key</a></li>
-      <li><a href="#add">Add registration IDs</a></li>
-      <li><a href="#remove">Remove registration IDs</a></li>
-      <li><a href="#upstream">Send upstream messages</a></li>
-      <li><a href="#response">Response formats</a></li>
+  <li><a href="#request">Request Format</a></li>
+  <li><a href="#create">Generate a Notification Key</a></li>
+  <li><a href="#add">Add Registration IDs</a></li>
+  <li><a href="#remove">Remove Registration IDs</a></li>
+  <li><a href="#upstream">Send Upstream Messages</a></li>
+  <li><a href="#response">Response Formats</a>
+    <ol class="toc">
+      <li><a href="#response-create">Create/add/remove operations</a>
+      <li><a href="#response-send">Send operations</a>
     </ol>
   </li>
 </ol>
@@ -38,32 +39,51 @@
 
 <p class="note"><strong>Note:</strong> To try out this feature, sign up using <a href="https://services.google.com/fb/forms/gcm/">this form</a>.</p>
 
-<p>The upstream messaging (device-to-cloud) feature described in this document is part of the Google Play services platform. Upstream messaging is available through the <a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">GoogleCloudMessaging</a> APIs. To use upstream messaging and the new streamlined registration process, you must <a href="{@docRoot}google/play-services/setup.html">set up</a> the Google Play services SDK.</p>
 
-<h2 id="what">What are User Notifications?</h2>
-
-<p>Third party servers can send a single message to multiple instance of an app running on devices owned by a single user. This feature is called <em>user notifications</em>. User notifications make it possible for every app instance that a user owns to reflect the latest messaging state. For example:</p>
+<p>With user notifications, 3rd-party app servers can send a single message to
+multiple instance of an app running on devices owned by a single user. This feature
+is called <em>user notifications</em>. User notifications make it possible for every
+app instance that a user owns to reflect the latest messaging state. For example:</p>
 
   <ul>
-  <li>If a message has been handled on one device, the GCM message on the other devices are dismissed. For example, if a user has handled a calendar notification on one device, the notification will go away on the user's other devices.</li>
-  <li>If a message has not been delivered yet to a device and but it has been handled, the GCM server removes it from the unsent queue for the other devices.</li>
-  <li>Likewise, a device can send messages to the {@code notification_key}, which is the token that GCM uses to fan out notifications to all devices whose registration IDs are associated with the key.</li>
+  <li>If a message has been handled on one device, the GCM message on the other
+devices are dismissed. For example, if a user has handled a calendar notification
+on one device, the notification will go away on the user's other devices.</li>
+
+  <li>If a message has not been delivered yet to a device and but it has been handled,
+the GCM server removes it from the unsent queue for the other devices.</li>
+
+  <li>Likewise, a device can send messages to the {@code notification_key}, which
+is the token that GCM uses to fan out notifications to all devices whose
+registration IDs are associated with the key.</li>
 </ul>
 
-<p>The way this works is that during registration, the 3rd-party server requests a {@code notification_key}. The {@code notification_key} maps a particular user to all of the user's associated registration IDs (a regID represents a particular Android application running on a particular device). Then instead of sending one message to one regID at a time, the 3rd-party server can send a message to to the {@code notification_key}, which then sends the message to all of the user's regIDs.</p>
+<p>The way this works is that during registration, the 3rd-party server requests
+a {@code notification_key}. The {@code notification_key} maps a particular user
+to all of the user's associated registration IDs (a regID represents a particular
+Android application running on a particular device). Then instead of sending one
+message to one regID at a time, the 3rd-party server can send a message to to the
+{@code notification_key}, which then sends the message to all of the user's regIDs.</p>
 
-<p class="note"><strong>Note:</strong> A notification dismissal message is like any other upstream message, meaning that it will be delivered to the other devices that belong to the specified {@code notification_key}. You should design your app to handle cases where the app receives a dismissal message, but has not yet displayed the notification that is being dismissed. You can solve this by caching the dismissal and then reconciling it with the corresponding notification.
+<p class="note"><strong>Note:</strong> A notification dismissal message is like any
+other upstream message, meaning that it will be delivered to the other devices that
+belong to the specified {@code notification_key}. You should design your app to
+handle cases where the app receives a dismissal message, but has not yet displayed
+the notification that is being dismissed. You can solve this by caching the dismissal
+and then reconciling it with the corresponding notification.
 </p>
 
-<p>You can use this feature with either the new <a href="ccs.html">GCM Cloud Connection Server</a> (CCS), or the older <a href="gcm.html">GCM HTTP server</a>.</p>
+<p>You can use this feature with either the <a href="ccs.html">XMPP</a> (CCS) or
+<a href="http.html">HTTP</a> connection server.</p>
 
 
-<h3 id="examples">Examples</h3>
+<p>The examples below show you how to perform generate/add/remove operations,
+and how to send upstream messages. For generate/add/remove operations, the
+message body is JSON.</p>
 
-<p>The examples in this section show you how to perform generate/add/remove operations, and how to send upstream messages. For generate/add/remove operations, the message body is JSON.</p>
-
-<h4 id="request">Request format</h4>
-<p>To send a  message, the application server issues a POST request to <code>https://android.googleapis.com/gcm/notification</code>.</p>
+<h2 id="request">Request Format</h2>
+<p>To send a  message, the application server issues a POST request to
+<code>https://android.googleapis.com/gcm/notification</code>.</p>
 
 <p>Here is the HTTP request header you should use for all create/add/remove operations:</p>
 
@@ -72,12 +92,22 @@
 Header: "Authorization", "key=API_KEY"
 </pre>
 
-<h4 id="create">Generate a notification key</h4>
+<h2 id="create">Generate a Notification Key</h2>
 
-<p>This example shows how to create a new <code>notification_key</code> for a <code>notification_key_name</code> called <code>appUser-Chris</code>. The {@code notification_key_name} is a name or identifier (can be a username for a 3rd-party app) that is unique to a given user. It is used by third parties to group together registration IDs for a single user. Note that <code>notification_key_name</code> and <code>notification_key</code> are unique to a group of registration IDs. It is also important that <code>notification_key_name</code> be uniquely named per app in case you have multiple apps for the same project ID. This ensures that notifications only go to the intended target app.</p>
+<p>This example shows how to create a new <code>notification_key</code> for a
+<code>notification_key_name</code> called <code>appUser-Chris</code>.
+The {@code notification_key_name} is a name or identifier (can be a username for
+a 3rd-party app) that is unique to a given user. It is used by third parties to
+group together registration IDs for a single user. Note that <code>notification_key_name</code>
+and <code>notification_key</code> are unique to a group of registration IDs. It is also
+important that <code>notification_key_name</code> be uniquely named per app in case
+you have multiple apps for the same project ID. This ensures that notifications
+only go to the intended target app.</p>
 
 
-<p>A create operation returns a token (<code>notification_key</code>). Third parties must save this token (as well as its mapping to the <code>notification_key_name</code>) to use in subsequent operations:</p>
+<p>A create operation returns a token (<code>notification_key</code>). Third parties
+must save this token (as well as its mapping to the <code>notification_key_name</code>)
+to use in subsequent operations:</p>
 
 <pre>request:
 { 
@@ -86,11 +116,14 @@
    &quot;registration_ids&quot;: [&quot;4&quot;, &quot;8&quot;, &quot;15&quot;, &quot;16&quot;, &quot;23&quot;, &quot;42&quot;]
 }</pre>
 
-<h4 id="add">Add registration IDs</h4>
+<h2 id="add">Add Registration IDs</h2>
 
-<p>This example shows how to add registration IDs for a given notification key. The maximum number of members allowed for a {@code notification_key} is 10.</p>
+<p>This example shows how to add registration IDs for a given notification key.
+The maximum number of members allowed for a {@code notification_key} is 10.</p>
 
-<p>Note that the <code>notification_key_name</code> is not strictly required for adding/removing regIDs. But including it protects you against accidentally using the incorrect <code>notification_key</code>.</p>
+<p>Note that the <code>notification_key_name</code> is not strictly required for
+adding/removing regIDs. But including it protects you against accidentally using
+the incorrect <code>notification_key</code>.</p>
 
 <pre>request:
 { 
@@ -100,7 +133,7 @@
    &quot;registration_ids&quot;: [&quot;4&quot;, &quot;8&quot;, &quot;15&quot;, &quot;16&quot;, &quot;23&quot;, &quot;42&quot;]
 }</pre>
 
-<h4 id="remove">Remove registration IDs</h4>
+<h2 id="remove">Remove Registration IDs</h2>
 
 <p>This example shows how to remove registration IDs for a given notification key:</p>
 <pre>request:
@@ -111,9 +144,14 @@
    &quot;registration_ids&quot;: [&quot;4&quot;, &quot;8&quot;, &quot;15&quot;, &quot;16&quot;, &quot;23&quot;, &quot;42&quot;]
 }</pre>
 
-<h4 id="upstream">Send upstream messages</h4>
+<h2 id="upstream">Send Upstream Messages</h2>
 
-<p>To send an upstream (device-to-cloud) message, you must use the <a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">GoogleCloudMessaging</a> API. Specifying a {@code notification_key} as the target for an upstream message allows a user on one device to send a message to other devices in the notification group&mdash;for example, to dismiss a notification. Here is an example that shows targeting a {@code notification_key}:</p>
+<p>To send an upstream (device-to-cloud) message, you must use the
+<a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">
+{@code GoogleCloudMessaging}</a> API. Specifying a {@code notification_key} as the target
+for an upstream message allows a user on one device to send a message to other
+devices in the notification group&mdash;for example, to dismiss a notification.
+Here is an example that shows targeting a {@code notification_key}:</p>
 
 <pre>GoogleCloudMessaging gcm = GoogleCloudMessaging.get(context);
 String to = NOTIFICATION_KEY;
@@ -125,17 +163,21 @@
 gcm.send(to, id, data);
 </pre>
 
-<p>This call generates the necessary XMPP stanza for sending the message. The Bundle data consists of a key-value pair.</p>
+<p>This call generates the necessary XMPP stanza for sending the message. The
+Bundle data consists of a key-value pair.</p>
 
-<p>For a complete example, see <a href="gs.html#gs_example">Getting Started</a>. 
+<p>For a complete example, see <a href="client.html">Implementing GCM Client</a>.
 
-<h4 id="response">Response formats</h4>
+<h2 id="response">Response Formats</h2>
 
-<p>This section shows examples of the responses that can be returned for notification key operations.</p>
+<p>This section shows examples of the responses that can be returned for
+notification key operations.</p>
 
-<h5>Response for create/add/remove operations</h5>
+<h3 id="response-create">Create/add/remove operations</h3>
 
-<p>When you make a request to create a {@code notification_key} or to add/remove its the wayregIDs, a successful response always returns the <code>notification_key</code>. This is the {@code notification_key} you will use for sending messages:</p>
+<p>When you make a request to create a {@code notification_key} or to add/remove its
+regIDs, a successful response always returns the <code>notification_key</code>.
+his is the {@code notification_key} you will use for sending messages:</p>
 
 <pre>HTTP status: 200
 { 
@@ -143,18 +185,23 @@
 }</pre>
 
 
-<h5>Response for send operations</h5>
+<h3 id="response-send">Send operations</h3>
 
-<p>For a send operation that has a {@code notification_key} as its target, the possible responses are success, partial success, and failure.</p>
+<p>For a send operation that has a {@code notification_key} as its target, the
+possible responses are success, partial success, and failure.</p>
 
-<p>Here is an example of "success"&mdash;the {@code notification_key} has 2 regIDs associated with it, and the message was successfully sent to both of them:</p>
+<p>Here is an example of "success"&mdash;the {@code notification_key} has 2 regIDs
+associated with it, and the message was successfully sent to both of them:</p>
 
 <pre>{
   "success": 2,
   "failure": 0
 }</pre>
 
-<p>Here is an example of "partial success"&mdash;the {@code notification_key} has 3 regIDs associated with it. The message was successfully send to 1 of the regIDs, but not to the other 2. The response message lists the regIDs that failed to receive the message:</p>
+<p>Here is an example of "partial success"&mdash;the {@code notification_key} has
+3 regIDs associated with it. The message was successfully send to 1 of the regIDs,
+but not to the other 2. The response message lists the regIDs that failed to
+receive the message:</p>
 
 <pre>{
   "success":1,
@@ -165,7 +212,9 @@
   ]
 }</pre>
 
-<p>In the case of failure, the response has HTTP code 503 and no JSON. When a message fails to be delivered to one or more of the regIDs associated with a {@code notification_key}, the 3rd-party server should retry.</p>
+<p>In the case of failure, the response has HTTP code 503 and no JSON. When a message
+fails to be delivered to one or more of the regIDs associated with a {@code notification_key},
+the 3rd-party server should retry.</p>
 
 
 
diff --git a/docs/html/google/gcm/server.jd b/docs/html/google/gcm/server.jd
index 92a1531..b5e6b48 100644
--- a/docs/html/google/gcm/server.jd
+++ b/docs/html/google/gcm/server.jd
@@ -1,36 +1,34 @@
-page.title=GCM Server
+page.title=Implementing GCM Server
 @jd:body
 
 <div id="qv-wrapper">
 <div id="qv">
 
-<h2>Quickview</h2>
-
-<ul>
-<li>Understand how to set up the server side of a GCM app.</li>
-<li>Become familiar with the <a href="{@docRoot}reference/com/google/android/gcm/server/package-summary.html">GCM server helper library</a>.</li>
-</ul>
-
-
 <h2>In this document</h2>
 
-<ol>
-  <li><a href="#requirements">Requirements</a> </li>
-  <li><a href="#gcm-setup">Setting Up GCM</a></li>
-  <li><a href="#server-setup">Setting Up an HTTP Server</a>
-    <ol>
-      <li><a href="#webserver-setup">Using a standard web server</a></li>
-      <li><a href="#appengine-setup">Using App Engine for Java</a></li>
+<ol class="toc">
+  <li><a href="#choose">Choosing a GCM Connection Server</a></li>
+  <li><a href="#role">Role of the 3rd-party Application Server</a></li>
+    <li><a href="#send-msg">Sending Messages</a>
+    <ol class="toc">
+
+      <li><a href="#target">Target</a></li>
+      <li><a href="#payload">Payload</a></li>
+      <li><a href="#params">Message parameters</a>
     </ol>
+    </li>
+  <li><a href="#receive">Receiving Messages</a> </li>
   </li>
+
 </ol>
 
 <h2>See Also</h2>
 
 <ol class="toc">
 <li><a href="gs.html">Getting Started</a></li>
-<li><a href="client.html">GCM Client</a></li>
-<li><a href="ccs.html">Cloud Connection Server</a></li>
+<li><a href="client.html">Implementing GCM Client</a></li>
+<li><a href="ccs.html">Cloud Connection Server (XMPP)</a></li>
+<li><a href="http.html">HTTP Connection Server</a></li>
 
 
 </ol>
@@ -39,122 +37,342 @@
 </div>
 
 
-
-
-<p>This document gives examples of GCM server-side code for HTTP. For an example of an XMPP server (<a href="ccs.html">Cloud Connection Server</a>), see <a href="gs.html#server">Getting Started</a>. Note that a full GCM implementation requires a client-side implementation, in addition to the server. For a complete working example that includes client and server-side code, see <a href="gs.html">Getting Started</a>.</a>
-
-<h2 id="requirements">Requirements</h2>
-<p>For the web server:</p>
+<p>The server side of GCM consists of 2 components:</p>
 <ul>
-  <li> <a href="http://ant.apache.org/">Ant 1.8</a> (it might work with earlier versions, but it's not guaranteed).</li>
-  <li>One of the following:
-    <ul>
-      <li>A running web server compatible with Servlets API version 2.5, such as <a href="http://tomcat.apache.org/">Tomcat 6</a> or <a href="http://jetty.codehaus.org/">Jetty</a>, or</li>
-      <li><a href="http://code.google.com/appengine/">Java App Engine SDK</a> version 1.6 or later.</li>
+<li>Google-provided <strong>GCM Connection Servers</strong>
+take messages from a 3rd-party application server and send them to a GCM-enabled
+Android application (the &quot;client app&quot;) running on a device. For example,
+Google provides connection servers for <a href="{@docRoot}google/gcm/http.html">
+HTTP</a> and <a href="{@docRoot}google/gcm/ccs.html">CCS</a> (XMPP).</li>
+<li>A <strong>3rd-party application server</strong> that you must implement. This application
+server sends data to a GCM-enabled Android application via the chosen GCM connection server.</li>
+</ul>
+</p>
+
+<p>Here are the basic steps you follow to implement your 3rd-party app server:</p>
+
+<ul>
+      <li>Decide which GCM connection server(s) you want to use. Note that if you want to use
+      upstream messaging from your client applications, you must use CCS. For a more detailed
+      discussion of this, see <a href="#choose">
+      Choosing a GCM Connection Server</a>.</li>
+      <li>Decide how you want to implement your app server. For example:
+        <ul>
+          <li>If you decide to use the HTTP connection server, you can use the
+GCM server helper library and demo app to help in implementing your app server.</li>
+          <li>If you decide to use the XMPP connection server, you can use
+the provided Python or Java <a href="http://www.igniterealtime.org/projects/smack/">
+Smack</a> demo apps as a starting point.</li>
+        <li>Note that Google AppEngine does not support connections to CCS.</li>
+        </ul>
+      </li>
     </ul>
   </li>
-  <li>A Google account registered to use GCM.</li>
-  <li>The API  key for that account.</li>
 </ul>
-<p>For the Android application:</p>
+
+<p>A full GCM implementation requires both a client implementation and a server
+implementation. For more
+information about implementing the client side, see <a href="client.html">
+Implementing GCM Client</a>.</p>
+
+<h2 id="choose">Choosing a GCM Connection Server</h2>
+
+<p>Currently GCM provides two connection servers: <a href="{@docRoot}google/gcm/http.html">
+HTTP</a> and <a href="{@docRoot}google/gcm/ccs.html">CCS</a> (XMPP). You can use them
+separately or in tandem. CCS messaging differs from GCM HTTP messaging in the following ways:</p>
 <ul>
-  <li>Emulator (or device) running Android 2.2 with Google APIs.</li>
-  <li>The Google API project number of the account registered to use GCM.</li>
+  <li>Upstream/Downstream messages
+    <ul>
+      <li>GCM HTTP: Downstream only: cloud-to-device. </li>
+      <li>CCS: Upstream and downstream (device-to-cloud, cloud-to-device). </li>
+    </ul>
+  </li>
+  <li>Asynchronous messaging
+    <ul>
+      <li>GCM HTTP: 3rd-party app servers send messages as HTTP POST requests and
+wait for a response. This mechanism is synchronous and causes the sender to block
+before sending another message.</li>
+      <li>CCS: 3rd-party app servers connect to Google infrastructure using a
+persistent XMPP connection and send/receive messages to/from all their devices
+at full line speed. CCS sends acknowledgment or failure notifications (in the
+form of special ACK and NACK JSON-encoded XMPP messages) asynchronously.</li>
+    </ul>
+  </li>
+
+  <li>JSON
+    <ul>
+      <li>GCM HTTP: JSON messages sent as HTTP POST.</li>
+      <li>CCS: JSON messages encapsulated in XMPP messages.</li>
+    </ul>
+  </li>
 </ul>
-<h2 id="gcm-setup">Setting Up GCM</h2>
-<p>Before proceeding with the server and client setup, it's necessary to register a Google account with the Google API Console, enable Google Cloud Messaging in GCM, and obtain an API key from the <a href="https://code.google.com/apis/console">Google API Console</a>.</p>
-<p>For instructions on how to set up GCM, see <a href="gs.html">Getting Started</a>.</p>
 
+<h2 id="role">Role of the 3rd-party Application Server</h2>
 
-<h2 id="server-setup">Setting Up an HTTP Server</h2>
-<p>This section describes the different options for setting up an HTTP server.</p>
-<h3 id="webserver-setup">Using a standard web server</h3>
-<p>To set up the server using a standard, servlet-compliant web server:</p>
+<p>Before you can write client Android applications that use the GCM feature, you must
+have an  application server that meets the following criteria:</p>
+
+<ul>
+  <li>Able to communicate with your client.</li>
+  <li>Able to  fire off properly formatted requests to the GCM server.</li>
+  <li>Able to handle requests and resend them as needed, using
+<a href="http://en.wikipedia.org/wiki/Exponential_backoff">exponential back-off.</a></li>
+  <li>Able to store the API key and client registration IDs. The
+API key is included in the header of POST requests that send
+messages.</li>
+ <li>Able to store the API key and client registration IDs.</li>
+ <li>Able to generate message IDs to uniquely identify each message it sends.</li>
+</ul>
+
+<h2 id="send-msg">Sending Messages</h2>
+
+<p>Here is the general sequence of events that occurs when a 3rd-party application
+server sends a message:</p>
 <ol>
-  <li>From the <a href="http://code.google.com/p/gcm">open source site</a>, download the following directories: <code>gcm-server</code>, <code>samples/gcm-demo-server</code>, and <code>samples/gcm-demo-appengine</code>.</p>
-
-
-  <li>In a text editor, edit the <code>samples/gcm-demo-server/WebContent/WEB-INF/classes/api.key</code> and replace the existing text with the API key obtained above.</li>
-  <li>In a shell window, go to the <code>samples/gcm-demo-server</code> directory.</li>
-  <li>Generate the server's WAR file by running <code>ant war</code>:</li>
-  
-  <pre class="prettyprint">$ ant war
-
-Buildfile:build.xml
-
-init:
-   [mkdir] Created dir: build/classes
-   [mkdir] Created dir: dist
-
-compile:
-   [javac] Compiling 6 source files to build/classes
-
-war:
-     [war] Building war: <strong>dist/gcm-demo.war</strong>
-
-BUILD SUCCESSFUL
-Total time: 0 seconds
-</pre>
-  
-  <li>Deploy the <code>dist/gcm-demo.war</code> to your running server. For instance, if you're using Jetty, copy <code>gcm-demo.war</code> to the <code>webapps</code> directory of the Jetty installation.</li>
-  <li>Open the server's main page in a browser. The URL depends on the server you're using and your machine's IP address, but it will be something like <code>http://192.168.1.10:8080/gcm-demo/home</code>, where <code>gcm-demo</code> is the application context and <code>/home</code> is the path of the main servlet.
-    
-  </li>
+  <li>The application server sends a message to GCM servers.</li>
+  <li>Google enqueues and stores the message in case the device is offline.</li>
+  <li>When the device is online, Google sends the message to the device.</li>
+  <li>On the device, the system broadcasts the message to the specified Android
+application via Intent broadcast with proper permissions, so that only the targeted
+ndroid application gets the message. This wakes the Android application up.
+The Android application does not need to be running beforehand to receive the message.</li>
+  <li>The Android application processes the message. </li>
 </ol>
-<p class="note"><strong>Note:</strong> You can get the IP by running <code>ifconfig</code> on Linux or MacOS, or <code>ipconfig</code> on Windows. </p>
 
-<p> You server is now ready.</p>
+<p>The following sections describe the basic requirements for
+sending messages.</p>
 
-<h3 id="appengine-setup">Using App Engine for Java</h3>
+<h3 id="target">Target</h3>
+<p>Required. When your app server sends a message in GCM, it must specify a target.</p>
+<p>For HTTP you must specify the target as one of:</p>
+<ul>
+<li><code>registration_ids</code>: For sending to 1 more more devices (up to 1000).
+When you send a message to multiple registration IDs, that is called a multicast message.</li>
+<li><code>notification_key</code>: For sending to multiple devices owned by a single user.</li>
+</ul>
+<p>For CCS (XMPP):</p>
+<ul>
+<li>You must specify the target as the &quot;to&quot; field, where the &quot;to&quot;
+field may contain a single registration ID or a notification key.
+CCS does not support multicast messaging.</li>
+</ul>
+<h3 id="payload">Payload</h3>
+<p>Optional. If you are including a payload in the message, you use the <code>data</code>
+parameter to include the payload. This applies for both HTTP and CCS.</p>
 
-<p>To set up the server using a standard App Engine for Java:</p>
+<h3 id="params">Message parameters</h3>
+
+<p>The following table lists the parameters that a 3rd-party app server might
+include in the JSON messages it sends to a connection server. See the "Where Supported"
+column for information about which connection servers support that particular
+parameter.</p>
+
+<p class="table-caption" id="table1">
+  <strong>Table 1.</strong> Message parameters.</p>
+
+<table>
+  <tr>
+    <th>Field</th>
+    <th>Description</th>
+<th>Where Supported</th>
+</tr>
+  <td><code>to</code></td>
+<td>In CCS, used in place of <code>registration_ids</code> to specify the
+recipient of a message. Its value must be a registration ID.
+The value is a string. Required.</td>
+<td>CCS</td>
+</tr>
+<tr>
+<td><code>message_id</code></td>
+<td>In CCS, uniquely identifies a message in an XMPP connection. The value is a
+string that uniquely identifies the associated message. The value is a string. Required.</td>
+<td>CCS</td>
+</tr>
+<tr>
+<td><code>message_type</code></td>
+<td>In CCS, indicates a special status message, typically sent by the system.
+However, your app server also uses this parameter to send an 'ack' or 'nack'
+message back to the CCS connection server. For more discussion of this topic, see
+<a href="ccs.html">Cloud Connection Server</a>. The value is a string. Optional.</td>
+<td>CCS</td>
+<tr>
+  <td><code>registration_ids</code></td>
+  <td>A string array with the list of devices (registration IDs) receiving the
+message. It must contain at least 1 and at most 1000 registration IDs. To send a
+multicast message, you must use JSON. For sending a single message to a single
+device, you could use a JSON object with just 1 registration id, or plain text
+(see below). A request must include a recipient&mdash;this can be either a
+registration ID, an array of registration IDs, or a {@code notification_key}.
+Required.</td>
+<td>HTTP</td>
+</tr>
+ <tr>
+    <td><code>notification_key</code></td>
+    <td>A string that maps a single user to multiple registration IDs associated
+with that user. This allows a 3rd-party server to send a single message to
+multiple app instances (typically on multiple devices) owned by a single user.
+A 3rd-party server can use {@code notification_key} as the target for a message
+instead of an individual registration ID (or array of registration IDs). The maximum
+number of members allowed for a {@code notification_key} is 10. For more discussion
+of this topic, see <a href="notifications.html">User Notifications</a>. Optional.
+</td>
+<td style="width:100px">HTTP. This feature is supported in CCS, but you use it by
+specifying a notification key in the &quot;to&quot; field.</td>
+</tr>
+  <tr>
+    <td><code>collapse_key</code></td>
+    <td>An arbitrary string (such as &quot;Updates Available&quot;) that is used
+to collapse a group of like messages
+when the device is offline, so that only the last message gets sent to the
+client. This is intended to avoid sending too many messages to the phone when it
+comes back online. Note that since there is no guarantee of the order in which
+messages get sent, the &quot;last&quot; message may not actually be the last
+message sent by the application server. Collapse keys are also called
+<a href="#s2s">send-to-sync messages</a>.
+<br>
+<strong>Note:</strong> GCM allows a maximum of 4 different collapse keys to be
+used by the GCM server
+at any given time. In other words, the GCM server can simultaneously store 4
+different send-to-sync messages per device, each with a different collapse key.
+If you exceed
+this number GCM will only keep 4 collapse keys, with no guarantees about which
+ones they will be. See <a href="adv.html#collapsible">Advanced Topics</a> for more
+discussion of this topic. Optional.</td>
+<td>CCS, HTTP</td>
+</tr>
+  <tr>
+    <td><code>data</code></td>
+    <td>A JSON object whose fields represents the key-value pairs of the message's
+payload data. If present, the payload data it will be
+included in the Intent as application data, with the key being the extra's name.
+For instance, <code>"data":{"score":"3x1"}</code> would result in an intent extra
+named <code>score</code> whose value is the string <code>3x1</code>.
+There is no limit on the number of key/value pairs, though there is a limit on
+the total size of the message (4kb). The values could be any JSON object, but we
+recommend using strings, since the values will be converted to strings in the GCM
+server anyway. If you want to include objects or other non-string data types
+(such as integers or booleans), you have to do the conversion to string yourself.
+Also note that the key cannot be a reserved word (<code>from</code> or any word
+starting with <code>google.</code>). To complicate things slightly, there are
+some reserved words (such as <code>collapse_key</code>) that are technically
+allowed in payload data. However, if the request also contains the word, the
+value in the request will overwrite the value in the payload data. Hence using
+words that are defined as field names in this table is not recommended, even in
+cases where they are technically allowed. Optional.</td>
+<td>CCS, HTTP</td>
+</tr>
+  <tr>
+    <td><code>delay_while_idle</code></td>
+    <td>If included, indicates that the message should not be sent immediately
+if the device is idle. The server will wait for the device to become active, and
+then only the last message for each <code>collapse_key</code> value will be
+sent. The default value is <code>false</code>, and must be a JSON boolean. Optional.</td>
+<td>CCS, HTTP</td>
+</tr>
+  <tr>
+    <td><code>time_to_live</code></td>
+    <td>How long (in seconds) the message should be kept on GCM storage if the
+device is offline. Optional (default time-to-live is 4 weeks, and must be set as
+a JSON number).</td>
+<td>CCS, HTTP</td>
+</tr>
+<tr>
+  <td><code>restricted_package_name</code></td>
+  <td>A string containing the package name of your application. When set, messages
+will only be sent to registration IDs that match the package name. Optional.
+  </td>
+<td>HTTP</td>
+</tr>
+<tr>
+  <td><code>dry_run</code></td>
+  <td>If included, allows developers to test their request without actually
+sending a message. Optional. The default value is <code>false</code>, and must
+be a JSON boolean.
+  </td>
+<td>HTTP</td>
+</tr>
+</table>
+
+<p>If you want to test your request (either JSON or plain text) without delivering
+the message to the devices, you can set an optional HTTP or JSON parameter called
+<code>dry_run</code> with the value <code>true</code>. The result will be almost
+identical to running the request without this parameter, except that the message
+will not be delivered to the devices. Consequently, the response will contain fake
+IDs for the message and multicast fields.</p>
+
+<h3 id="plain-text">Plain text (HTTP only)</h3>
+
+<p>If you are using plain text instead of JSON, the message fields must be set as
+HTTP parameters sent in the body, and their syntax is slightly different, as
+described below:
+<table>
+  <tr>
+    <th>Field</th>
+    <th>Description</th>
+  </tr>
+  <tr>
+    <td><code>registration_id</code></td>
+    <td>Must contain the registration ID of the single device receiving the message.
+Required.</td>
+  </tr>
+  <tr>
+    <td><code>collapse_key</code></td>
+    <td>Same as JSON (see previous table). Optional.</td>
+  </tr>
+  <tr>
+    <td><code>data.&lt;key&gt;</code></td>
+
+    <td>Payload data, expressed as parameters prefixed with <code>data.</code> and
+suffixed as the key. For instance, a parameter of <code>data.score=3x1</code> would
+result in an intent extra named <code>score</code> whose value is the string
+<code>3x1</code>. There is no limit on the number of key/value parameters, though
+there is a limit on the total size of the  message. Also note that the key cannot
+be a reserved word (<code>from</code> or any word starting with
+<code>google.</code>). To complicate things slightly, there are some reserved words
+(such as <code>collapse_key</code>) that are technically allowed in payload data.
+However, if the request also contains the word, the value in the request will
+overwrite the value in the payload data. Hence using words that are defined as
+field names in this table is not recommended, even in cases where they are
+technically allowed. Optional.</td>
+
+  </tr>
+  <tr>
+    <td><code>delay_while_idle</code></td>
+    <td>Should be represented as <code>1</code> or <code>true</code> for
+<code>true</code>, anything else for <code>false</code>. Optional. The default
+value is <code>false</code>.</td>
+  </tr>
+  <tr>
+    <td><code>time_to_live</code></td>
+    <td>Same as JSON (see previous table). Optional.</td>
+  </tr>
+<tr>
+  <td><code>restricted_package_name</code></td>
+  <td>Same as JSON (see previous table). Optional.
+  </td>
+</tr>
+<tr>
+  <td><code>dry_run</code></td>
+  <td>Same as JSON (see previous table). Optional.
+  </td>
+</tr>
+</table>
+
+<h2 id="receive">Receiving Messages</h2>
+
+<p>This is the sequence of events that occurs when an Android application
+installed on a mobile device receives a message:</p>
+
 <ol>
-  <li>Get the files from the <a href="http://code.google.com/p/gcm">open source site</a>, as described above.</p>
-  </li>
-  <li>In a text editor, edit <code>samples/gcm-demo-appengine/src/com/google/android/gcm/demo/server/ApiKeyInitializer.java</code> and replace the existing text with the API key obtained above.
-
-  <p class="note"><strong>Note:</strong> The API key value set in that class will be used just once to create a persistent entity on App Engine. If you deploy the application, you can use App Engine's <code>Datastore Viewer</code> to change it later.</p>
-  
-  </li>
-  <li>In a shell window, go to the <code>samples/gcm-demo-appengine</code> directory.</li>
-  <li>Start the development App Engine server by <code>ant runserver</code>, using the <code>-Dsdk.dir</code> to indicate the location of the App Engine SDK and <code>-Dserver.host</code> to set your server's hostname or IP address:</li>
-
-<pre class="prettyprint">
-$ ant -Dsdk.dir=/opt/google/appengine-java-sdk runserver -Dserver.host=192.168.1.10
-Buildfile: gcm-demo-appengine/build.xml
-
-init:
-    [mkdir] Created dir: gcm-demo-appengine/dist
-
-copyjars:
-
-compile:
-
-datanucleusenhance:
-  [enhance] DataNucleus Enhancer (version 1.1.4) : Enhancement of classes
-  [enhance] DataNucleus Enhancer completed with success for 0 classes. Timings : input=28 ms, enhance=0 ms, total=28 ms. Consult the log for full details
-  [enhance] DataNucleus Enhancer completed and no classes were enhanced. Consult the log for full details
-
-runserver:
-     [java] Jun 15, 2012 8:46:06 PM com.google.apphosting.utils.jetty.JettyLogger info
-     [java] INFO: Logging to JettyLogger(null) via com.google.apphosting.utils.jetty.JettyLogger
-     [java] Jun 15, 2012 8:46:06 PM com.google.apphosting.utils.config.AppEngineWebXmlReader readAppEngineWebXml
-     [java] INFO: Successfully processed gcm-demo-appengine/WebContent/WEB-INF/appengine-web.xml
-     [java] Jun 15, 2012 8:46:06 PM com.google.apphosting.utils.config.AbstractConfigXmlReader readConfigXml
-     [java] INFO: Successfully processed gcm-demo-appengine/WebContent/WEB-INF/web.xml
-     [java] Jun 15, 2012 8:46:09 PM com.google.android.gcm.demo.server.ApiKeyInitializer contextInitialized
-     [java] SEVERE: Created fake key. Please go to App Engine admin console, change its value to your API Key (the entity type is 'Settings' and its field to be changed is 'ApiKey'), then restart the server!
-     [java] Jun 15, 2012 8:46:09 PM com.google.appengine.tools.development.DevAppServerImpl start
-     [java] INFO: The server is running at http://192.168.1.10:8080/
-     [java] Jun 15, 2012 8:46:09 PM com.google.appengine.tools.development.DevAppServerImpl start
-     [java] INFO: The admin console is running at http://192.168.1.10:8080/_ah/admin
-</pre>
-
-  <li>Open the server's main page in a browser. The URL depends on the server you're using and your machine's IP address, but it will be something like <code>http://192.168.1.10:8080/home</code>, where <code>/home</code> is the path of the main servlet.</li>
-  
-  <p class="note"><strong>Note:</strong> You can get the IP by running <code>ifconfig</code> on Linux or MacOS, or <code>ipconfig</code> on Windows.</p>
-  
+  <li>The system receives the incoming message and extracts the raw key/value
+pairs from the message payload, if any.</li>
+  <li>The system passes the key/value pairs to the targeted Android application
+in a <code>com.google.android.c2dm.intent.RECEIVE</code> Intent as a set of
+extras.</li>
+  <li>The Android application extracts the raw data
+from the <code>com.google.android.c2dm.intent.RECEIVE</code><code> </code>Intent
+by key and processes the data.</li>
 </ol>
-<p> You server is now ready.</p>
 
-
+<p>See the documentation for each connection server for more detail on how it
+handles responses.</p>
diff --git a/docs/html/google/google_toc.cs b/docs/html/google/google_toc.cs
index 77042d3..2ded286 100644
--- a/docs/html/google/google_toc.cs
+++ b/docs/html/google/google_toc.cs
@@ -133,29 +133,32 @@
 
 
 
-  <li class="nav-section">
+   <li class="nav-section">
       <div class="nav-section-header"><a href="<?cs var:toroot ?>google/gcm/index.html">
         <span class="en">Google Cloud Messaging</span></a>
       </div>
       <ul>
+        <li><a href="<?cs var:toroot?>google/gcm/gcm.html">
+            <span class="en">Overview</span></a>
+        </li>
         <li><a href="<?cs var:toroot?>google/gcm/gs.html">
             <span class="en">Getting Started</span></a>
         </li>
-        <li><a href="<?cs var:toroot?>google/gcm/gcm.html">
-            <span class="en">Architectural Overview</span></a>
+        <li><a href="<?cs var:toroot?>google/gcm/client.html">
+            <span class="en">Implementing GCM Client</span></a>
         </li>
-         <li><a href="<?cs var:toroot?>google/gcm/ccs.html">
-              <span class="en">Cloud Connection Server</span></a>
+        <li class="nav-section"><div class="nav-section-header"><a href="<?cs var:toroot?>google/gcm/server.html">
+              <span class="en">Implementing GCM Server</span></a></div>
+              <ul>
+              <li><a href="<?cs var:toroot?>google/gcm/ccs.html">
+              <span class="en">CCS (XMPP)</span></a></li>
+              <li><a href="<?cs var:toroot?>google/gcm/http.html">
+              <span class="en">HTTP</span></a></li>
+              </ul>
         </li>
         <li><a href="<?cs var:toroot?>google/gcm/notifications.html">
               <span class="en">User Notifications</span></a>
         </li>
-        <li><a href="<?cs var:toroot?>google/gcm/client.html">
-            <span class="en">GCM Client</span></a>
-        </li>
-        <li><a href="<?cs var:toroot?>google/gcm/server.html">
-            <span class="en">GCM Server</span></a>
-        </li>
         <li><a href="<?cs var:toroot?>google/gcm/adv.html">
             <span class="en">Advanced Topics</span></a>
         </li>
diff --git a/docs/html/google/play-services/setup.jd b/docs/html/google/play-services/setup.jd
index 6553c18..fb656b7 100644
--- a/docs/html/google/play-services/setup.jd
+++ b/docs/html/google/play-services/setup.jd
@@ -1,6 +1,24 @@
 page.title=Set Up Google Play Services SDK
 @jd:body
 
+
+
+<div id="qv-wrapper">
+<div id="qv">
+
+<h2>In this document</h2>
+<ol>
+  <li><a href="#Install">Install the Google Play Services SDK</a></li>
+  <li><a href="#Setup">Set Up a Project that Uses Google Play Services</a></li>
+  <li><a href="#Proguard">Create a Proguard Exception</a></li>
+  <li><a href="#ensure">Ensure Devices Have the Google Play services APK</a></li>
+</ol>
+
+
+</div>
+</div>
+
+
     
 <p>To develop an app using the <a href="{@docRoot}reference/gms-packages.html">Google
 Play services APIs</a>, you must download the Google Play services SDK
@@ -10,7 +28,7 @@
 <p>To test your app when using the Google Play services SDK, you must use either:</p>
 <ul>
   <li>A compatible Android
-    device that runs Android 2.2 or higher and includes Google Play Store.</li>
+    device that runs Android 2.3 or higher and includes Google Play Store.</li>
   <li>The Android emulator with an <a href="{@docRoot}tools/devices/index.html">AVD</a>
   that runs the Google APIs platform based on Android 4.2.2 or higher.</li>
 </ul>
@@ -24,9 +42,12 @@
 <p>To install the Google Play services SDK for development:</p>
 
 <ol>
-  <li>Launch the SDK Manager.
+  <li>Launch the SDK Manager in one of the following ways:
    <ul>
-    <li>From Eclipse (with <a href="{@docRoot}tools/help/adt.html">ADT</a>),
+    <li>In Android Studio, click <strong>SDK Manager</strong>
+<img src="{@docRoot}images/tools/sdk-manager-studio.png" style="vertical-align:bottom;margin:0;height:19px" />
+in the toolbar.</li>
+    <li>In Eclipse (with <a href="{@docRoot}tools/help/adt.html">ADT</a>),
     select <strong>Window</strong> &gt; <strong>Android SDK Manager</strong>.</li>
     <li>On Windows, double-click the <code>SDK Manager.exe</code> file at the root of the Android
   SDK directory.</li>
@@ -36,19 +57,25 @@
   </li>
   <li>Install the Google Play services SDK.
     <p>Scroll to the bottom of the package list, expand <b>Extras</b>, select
-    <b>Google Play services</b>, and install it.</p>
+    <b>Google Play services</b>, and install it. If you're using Android Studio, also install
+    <b>Google Repository</b> (it provides the Maven repository used for Gradle builds).</p>
       <p>The Google Play services SDK is saved in your Android SDK environment at
       <code>&lt;android-sdk&gt;/extras/google/google_play_services/</code>.</p>
+
+<p class="note"><strong>Note:</strong> Google Play services 4.0.30 (released
+November 2013) and newer versions require Android 2.3 or higher. If your app supports Android 2.2,
+you can continue development with the Google Play services SDK, but must instead install
+<b>Google Play services for Froyo</b> from the SDK Manager.</p>
+
   </li>
   <li>Install a compatible version of the Google APIs platform.
     <p>If you want to test your app on the emulator, expand the directory for <b>Android 4.2.2
     (API 17)</b> or a higher version, select <b>Google APIs</b>, and install it. Then create a
     new <a href="{@docRoot}tools/devices/index.html">AVD</a> with Google APIs as
     the platform target.</p>
-    <p class="note"><strong>Note:</strong> Only Android 4.2.2 and higher versions of the
-    Google APIs platform include Google Play services.</p>
   </li>
   <li>Make a copy of the Google Play services library project.
+    <p class="note"><strong>Note:</strong> If you are using Android Studio, skip this step.</p>
     <p>Copy the library project at
   <code>&lt;android-sdk&gt;/extras/google/google_play_services/libproject/google-play-services_lib/</code>        
   to the location where you maintain your Android app projects.
@@ -60,23 +87,59 @@
 
 
 
-<h2 id="Setup">Set Up a Project with the Library</h2>
+<h2 id="Setup">Set Up a Project that Uses Google Play Services</h2>
 
-<p>To set up a project to use the Google Play services SDK:</p>
+<p><b>Using Android Studio:</b></p>
 
 <ol>
-  <li>Reference the library project in your Android project.
-      <p>See the 
-      <a href="{@docRoot}tools/projects/projects-eclipse.html#ReferencingLibraryProject">Referencing a Library Project for Eclipse</a>
-      or <a href="{@docRoot}tools/projects/projects-cmdline.html#ReferencingLibraryProject">Referencing a Library Project on the Command Line</a>
-      for more information on how to do this.</p>
-      <p class="note"><strong>Note:</strong>
-      You should be referencing a copy of the library that you copied to your development
-      workspace&mdash;you should not reference the library directly from the Android SDK directory.</p>
+  <li>Open the <code>build.gradle</code> file inside your application directory.</li>
+  <li>Add a new build rule under <code>dependencies</code> for the latest version of
+<code>play-services</code>. For example:
+<pre class="no-pretty-print">
+apply plugin: 'android'
+...
+
+dependencies {
+    compile 'com.android.support:appcompat-v7:+'
+    <strong>compile 'com.google.android.gms:play-services:4.0.30'</strong>
+}
+</pre>
+<p>Be sure you update this version number each time Google Play services is updated.</p>
   </li>
-  <li>If you are using <a href="{@docRoot}tools/help/proguard.html">ProGuard</a>, add the following
-      lines in the <code>&lt;project_directory&gt;/proguard-project.txt</code> file
-      to prevent ProGuard from stripping away required classes:
+  <li>Save the changes and click <strong>Sync Project with Gradle Files</strong>
+<img src="{@docRoot}images/tools/sync-project.png" style="vertical-align:bottom;margin:0;height:19px" />
+in the toolbar.
+  </li>
+</ol>
+
+<p>You can now begin developing features with the
+<a href="{@docRoot}reference/gms-packages.html">Google Play services APIs</a>.</p>
+
+
+<p><b>Using Eclipse or another IDE:</b></p>
+
+<p>To make the Google Play services APIs available to your app, you must reference the library
+project you created in step 4 of the <a href="#Install">installation instructions</a>.</p>
+<p>See the <a href="{@docRoot}tools/projects/projects-eclipse.html#ReferencingLibraryProject"
+>Referencing a Library Project for Eclipse</a> or <a
+href="{@docRoot}tools/projects/projects-cmdline.html#ReferencingLibraryProject">Referencing a
+Library Project on the Command Line</a> for more information on how to do this.</p>
+
+<p class="note"><strong>Note:</strong>
+You should be referencing a copy of the library that you copied to your development
+workspace&mdash;you should not reference the library directly from the Android SDK directory.</p>
+
+<p>Once you've set up your project to reference the library project,
+you can begin developing features with the
+<a href="{@docRoot}reference/gms-packages.html">Google Play services APIs</a>.</p>
+
+
+
+<h2 id="Proguard">Create a Proguard Exception</h2>
+
+<p>To prevent <a href="{@docRoot}tools/help/proguard.html">ProGuard</a> from stripping away
+required classes, add the following lines in the
+<code>&lt;project_directory&gt;/proguard-project.txt</code> file:
 <pre>
 -keep class * extends java.util.ListResourceBundle {
     protected Object[][] getContents();
@@ -95,11 +158,13 @@
     public static final ** CREATOR;
 }
 </pre>
+
+<p class="note"><strong>Note:</strong> When using Android Studio, you must add Proguard
+to your <code>gradle.build</code> file's build types. For more information, see the
+<a href="http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Running-ProGuard"
+>Gradle Plugin User Guide</a>.
 </ol>
 
-<p>Once you have the Google Play services library project added to your app project,
-you can begin developing features with the
-<a href="{@docRoot}reference/gms-packages.html">Google Play services APIs</a>.</p>
 
 
 
@@ -191,4 +256,4 @@
   to display an error message to the user, which allows the user to download the APK
   from the Google Play Store or enable it in the device's system settings.
     </li>
-</ol>
\ No newline at end of file
+</ol>
diff --git a/docs/html/guide/guide_toc.cs b/docs/html/guide/guide_toc.cs
index 84ffd05..8f2795a 100644
--- a/docs/html/guide/guide_toc.cs
+++ b/docs/html/guide/guide_toc.cs
@@ -490,11 +490,8 @@
     <span class="en">Web Apps</span>
     </a></div>
     <ul>
-      <li><a href="<?cs var:toroot ?>guide/webapps/overview.html">
-            <span class="en">Overview</span>
-          </a></li>
       <li><a href="<?cs var:toroot ?>guide/webapps/targeting.html">
-            <span class="en">Targeting Screens from Web Apps</span>
+            <span class="en">Supporting Different Screens in Web Apps</span>
           </a></li>
       <li><a href="<?cs var:toroot ?>guide/webapps/webview.html">
             <span class="en">Building Web Apps in WebView</span>
diff --git a/docs/html/guide/topics/manifest/uses-permission-element.jd b/docs/html/guide/topics/manifest/uses-permission-element.jd
index 8e9e795..bd7091e 100644
--- a/docs/html/guide/topics/manifest/uses-permission-element.jd
+++ b/docs/html/guide/topics/manifest/uses-permission-element.jd
@@ -35,7 +35,8 @@
 </div>
 
 <dt>syntax:</dt>
-<dd><pre class="stx">&lt;uses-permission android:<a href="#nm">name</a>="<i>string</i>" /&gt;</pre></dd>
+<dd><pre class="stx">&lt;uses-permission android:<a href="#nm">name</a>="<i>string</i>"
+        android:<a href="#maxSdk">maxSdkVersion</a>="<i>integer</i>" /&gt;</pre></dd>
 
 <dt>contained in:</dt>
 <dd><code><a href="{@docRoot}guide/topics/manifest/manifest-element.html">&lt;manifest&gt;</a></code></dd>
@@ -63,6 +64,25 @@
 or "{@code android.permission.READ_CONTACTS}".  As these examples show, 
 a permission name typically includes the package name as a prefix.</dd>
 
+<dt><a name="maxSdk"></a>{@code android:maxSdkVersion}</dt>
+<dd>The highest API level at which this permission should be granted to your app.
+Setting this attribute is useful if the permission your app requires is no longer needed beginning
+at a certain API level.
+<p>For example, beginning with Android 4.4 (API level 19), it's no longer necessary for your app
+to request the {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} permission when your
+app wants to write to its own application-specific directories on external storage (the directories
+provided by {@link android.content.Context#getExternalFilesDir getExternalFilesDir()}). However,
+the permission <em>is required</em> for API level 18 and lower. So you can declare that this
+permission is needed only up to API level 18 with a declaration such as this:
+<pre>
+&lt;uses-permission
+     android:name="android.permission.WRITE_EXTERNAL_STORAGE"
+     android:maxSdkVersion="18" />
+</pre>
+<p>This way, beginning with API level 19, the system will no longer grant your app the
+{@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} permission.</p>
+</dd>
+
 </dl></dd>
 
 <!-- ##api level indication## -->
diff --git a/docs/html/guide/webapps/best-practices.jd b/docs/html/guide/webapps/best-practices.jd
index 1362990..a13c69da 100644
--- a/docs/html/guide/webapps/best-practices.jd
+++ b/docs/html/guide/webapps/best-practices.jd
@@ -1,6 +1,24 @@
 page.title=Best Practices for Web Apps
 @jd:body
 
+<div id="qv-wrapper">
+<div id="qv">
+
+<h2>See also</h2>
+<ul>
+  <li><a href="https://developers.google.com/chrome/mobile/docs/webview/pixelperfect"
+  >Pixel-Perfect UI in the WebView</a></li>
+  <li><a href="http://www.html5rocks.com/en/mobile/responsivedesign/" class="external-link">Creating
+  a Mobile-First Responsive Web Design</a></li>
+  <li><a href="http://www.html5rocks.com/en/mobile/high-dpi/" class="external-link">High
+  DPI Images for Variable Pixel Densities</a></li>
+</ul>
+
+</div>
+</div>
+
+
+
 <style>
 .bold li {
   font-weight:bold;
diff --git a/docs/html/guide/webapps/debugging.jd b/docs/html/guide/webapps/debugging.jd
index 1eef1ae..3c95fc2 100644
--- a/docs/html/guide/webapps/debugging.jd
+++ b/docs/html/guide/webapps/debugging.jd
@@ -18,19 +18,29 @@
 
 <h2>See also</h2>
 <ol>
+  <li><a class="external-link"
+href="https://developers.google.com/chrome-developer-tools/docs/remote-debugging">Remote
+Debugging on Android</a></li>
   <li><a href="{@docRoot}tools/debugging/index.html">Debugging</a></li>
 </ol>
 
 </div>
 </div>
 
-<p>If you're developing a web application for Android, you can debug your JavaScript
-using the {@code console} JavaScript APIs, which output messages to logcat. If you're familiar with
+<p>If you are testing your web app with a device running Android 4.4 or higher,
+you can remotely debug your web pages in {@link android.webkit.WebView} with
+Chrome Developer Tools, while continuing to support older versions of Android.
+For more information, see <a class="external-link"
+href="https://developers.google.com/chrome-developer-tools/docs/remote-debugging">Remote
+Debugging on Android</a>.</p>
+
+<p>If you don't have a device running Android 4.4 or higher, you can debug your JavaScript using the
+{@code console} JavaScript APIs and view the output messages to logcat. If you're familiar with
 debugging web pages with Firebug or Web Inspector, then you're probably familiar
 with using {@code console} (such as {@code console.log()}). Android's WebKit framework supports most
 of the same APIs, so you can receive logs from your web page when debugging in Android's Browser
-or in your own {@link android.webkit.WebView}.</p>
-
+or in your own {@link android.webkit.WebView}. This document describes how to use the
+console APIs for debugging.</p>
 
 
 <h2 id="Browser">Using Console APIs in the Android Browser</h2>
@@ -83,28 +93,17 @@
 
 <h2 id="WebView">Using Console APIs in WebView</h2>
 
-<p>If you've implemented a custom {@link android.webkit.WebView} in your application, all the
-same console APIs are supported when debugging your web page in WebView. On Android
-1.6 and lower, console messages are automatically sent to logcat with the
-"WebCore" logging tag. If you're targeting Android 2.1 (API Level 7) or higher, then you must
+<p>All the console APIs shown above are also
+supported when debugging in {@link android.webkit.WebView}. 
+If you're targeting Android 2.1 (API level 7) and higher, you must
 provide a {@link android.webkit.WebChromeClient}
 that implements the {@link android.webkit.WebChromeClient#onConsoleMessage(String,int,String)
-onConsoleMessage()} callback method, in order for console messages to appear in logcat.</p>
-
-<p>Additionally, the {@link
-android.webkit.WebChromeClient#onConsoleMessage(String,int,String)} method introduced in API
-Level 7 has been deprecated in favor of {@link
-android.webkit.WebChromeClient#onConsoleMessage(ConsoleMessage)} in API Level 8.</p>
-
-<p>Whether you're developing for Android 2.1 (API Level 7) or Android 2.2 (API Level 8 or
-greater), you must implement {@link android.webkit.WebChromeClient} and override the appropriate
-{@link
-android.webkit.WebChromeClient#onConsoleMessage(String,int,String) onConsoleMessage()} callback
-method. Then, apply the {@link android.webkit.WebChromeClient} to your {@link
+onConsoleMessage()} method in order for console messages to appear in logcat.
+Then, apply the {@link android.webkit.WebChromeClient} to your {@link
 android.webkit.WebView} with {@link android.webkit.WebView#setWebChromeClient(WebChromeClient)
 setWebChromeClient()}.
 
-<p>Using API Level 7, this is how your code for {@link
+<p>For example, to support API level 7, this is how your code for {@link
 android.webkit.WebChromeClient#onConsoleMessage(String,int,String)} might look:</p>
 
 <pre>
@@ -118,8 +117,8 @@
 });
 </pre>
 
-<p>With API Level 8 or greater, your code for {@link
-android.webkit.WebChromeClient#onConsoleMessage(ConsoleMessage)} might look like this:</p>
+<p>However, if your lowest supported version is API level 8 or higher, you should instead
+implement {@link android.webkit.WebChromeClient#onConsoleMessage(ConsoleMessage)}. For example:</p>
 
 <pre>
 WebView myWebView = (WebView) findViewById(R.id.webview);
@@ -134,8 +133,8 @@
 </pre>
 
 <p>The {@link android.webkit.ConsoleMessage} also includes a {@link
-android.webkit.ConsoleMessage.MessageLevel MessageLevel} to indicate the type of console message
-being delivered. You can query the message level with {@link
+android.webkit.ConsoleMessage.MessageLevel MessageLevel} object to indicate the type of console
+message being delivered. You can query the message level with {@link
 android.webkit.ConsoleMessage#messageLevel()} to determine the severity of the message, then
 use the appropriate {@link android.util.Log} method or take other appropriate actions.</p>
 
diff --git a/docs/html/guide/webapps/index.jd b/docs/html/guide/webapps/index.jd
index df7ddbe..a188d2b 100644
--- a/docs/html/guide/webapps/index.jd
+++ b/docs/html/guide/webapps/index.jd
@@ -1,16 +1,50 @@
 page.title=Web Apps
-page.landing=true
-page.landing.intro=Android has always been about connectivity and providing a great web browsing experience, so building your app with web technologies can be a great opportunity. Not only can you build an app on the web and still optimize your designs for Android's various screen sizes and densities, but you can also embed web-based content into your Android app using WebView.
-page.landing.image=
 
 @jd:body
 
-<div class="landing-docs">
+<div class="figure" style="width:327px">
+  <img src="{@docRoot}images/webapps/webapps.png" alt="" />
+  <p class="img-caption"><strong>Figure 1.</strong> You can make your web content available to
+users in two ways: in a traditional web browser and in an Android application, by
+including a WebView in the layout.</p>
+</div>
 
-  <div class="col-6">
-  </div>
+<p>There are essentially two ways to deliver an application on Android: as a
+client-side application (developed using the Android SDK and installed on user devices in an APK)
+or as a web application (developed using web standards and accessed through a web
+browser&mdash;there's nothing to install on user devices).</p>
 
-  <div class="col-6">
-  </div>
+<p>If you chose to provide a web-based app for Android-powered devices, you can rest
+assured that major web browsers for Android (and the {@link android.webkit.WebView} framework)
+allow you to specify viewport and style properties that make your web pages appear at the proper
+size and scale on all screen configurations.</p>
 
-</div>
\ No newline at end of file
+<p>Figure 1 illustrates how you can provide access to your web pages from either
+a web browser or your your own Android app. However, you shouldn't develop an Android
+app simply as a means to view your web site. Rather, the web pages you embed in your
+Android app should be designed especially for that environment. You can even define an
+interface between your Android application and your web pages that allows JavaScript in the web
+pages to call upon APIs in your Android application&mdash;providing Android APIs to your web-based
+application.</p>
+
+<p>To start developing web pages for Android-powered devices, see the following documents:</p>
+
+<dl>
+  <dt><a href="{@docRoot}guide/webapps/targeting.html"><strong>Supporting Different Screens from Web
+  Apps</strong></a></dt>
+  <dd>How to properly size your web app on Android-powered devices and support
+multiple screen densities. The information in this document is important if you're building a web
+application that you at least expect to be available on Android-powered devices (which you should
+assume for anything you publish on the web), but especially if you're targeting mobile devices
+or using {@link android.webkit.WebView}.</dd>
+  <dt><a href="{@docRoot}guide/webapps/webview.html"><strong>Building Web Apps in
+WebView</strong></a></dt>
+  <dd>How to embed web pages into your Android application using {@link
+  android.webkit.WebView} and bind JavaScript to Android APIs.</dd>
+  <dt><a href="{@docRoot}guide/webapps/debugging.html"><strong>Debugging Web Apps</strong></a></dt>
+  <dd>How to debug web apps using JavaScript Console APIs.</dd>
+  <dt><a href="{@docRoot}guide/webapps/best-practices.html"><strong>Best Practices for Web
+Apps</strong></a></dt>
+  <dd>A list of practices you should follow, in order to provide an effective web application on
+Android-powered devices.</dd>
+</dl>
\ No newline at end of file
diff --git a/docs/html/guide/webapps/overview.jd b/docs/html/guide/webapps/overview.jd
deleted file mode 100644
index 069290a..0000000
--- a/docs/html/guide/webapps/overview.jd
+++ /dev/null
@@ -1,71 +0,0 @@
-page.title=Web Apps Overview
-@jd:body
-
-<div class="figure" style="width:327px">
-  <img src="{@docRoot}images/webapps/webapps.png" alt="" />
-  <p class="img-caption"><strong>Figure 1.</strong> You can make your web content available to
-users in two ways: in a traditional web browser and in an Android application, by
-including a WebView in the layout.</p>
-</div>
-
-<p>There are essentially two ways to deliver an application on Android: as a
-client-side application (developed using the Android SDK and installed on user devices as an {@code
-.apk}) or as a web application (developed using web standards and accessed through a web
-browser&mdash;there's nothing to install on user devices).</p>
-
-<p>The approach you choose for your application could depend on several factors, but Android makes
-the decision to develop a web application easier by providing:</p>
-<ul>
-  <li>Support for viewport properties that allow you to properly size your web application
-based on the screen size</li>
-  <li>CSS and JavaScript features that allow you to provide different styles and images
-based on the screen's pixel density (screen resolution)</li>
-</ul>
-
-<p>Thus, your decision to develop a web application for Android can exclude consideration for
-screen support, because it's already easy to make your web pages look good on all types of screens
-powered by Android.</p>
-
-<p>Another great feature of Android is that you don't have to build your application purely on
-the client or purely on the web. You can mix the two together by developing a client-side Android
-application that embeds some web pages (using a {@link android.webkit.WebView} in your Android
-application layout). Figure 1 visualizes how you can provide access to your web pages from either
-a web browser or your Android application. However, you shouldn't develop an Android
-application simply as a means to launch your web site. Rather, the web pages you embed in your
-Android application should be designed especially for that environment. You can even define an
-interface between your Android application and your web pages that allows JavaScript in the web
-pages to call upon APIs in your Android application&mdash;providing Android APIs to your web-based
-application.</p>
-
-<p>Since Android 1.0, {@link android.webkit.WebView} has been available for Android
-applications to embed web content in their layout and bind JavaScript to Android APIs. After
-Android added support for more screen densities (adding support for high and low-density
-screens), Android 2.0 added features to the WebKit framework to allow web pages to specify
-viewport properties and query the screen density in order to modify styles
-and image assets, as mentioned above. Because these features are a part of Android's WebKit
-framework, both the Android Browser (the default web browser provided with the platform) and
-{@link android.webkit.WebView} support the same viewport and screen density features.</p>
-
-<p>To develop a web application for Android-powered devices, you should read the
-following documents:</p>
-
-<dl>
-  <dt><a href="{@docRoot}guide/webapps/targeting.html"><strong>Targeting Screens from Web
-Apps</strong></a></dt>
-  <dd>How to properly size your web app on Android-powered devices and support
-multiple screen densities. The information in this document is important if you're building a web
-application that you at least expect to be available on Android-powered devices (which you should
-assume for anything you publish on the web), but especially if you're targeting mobile devices
-or using {@link android.webkit.WebView}.</dd>
-  <dt><a href="{@docRoot}guide/webapps/webview.html"><strong>Building Web Apps in
-WebView</strong></a></dt>
-  <dd>How to embed web pages into your Android application using {@link android.webkit.WebView} and
-bind JavaScript to Android APIs.</dd>
-  <dt><a href="{@docRoot}guide/webapps/debugging.html"><strong>Debugging Web Apps</strong></a></dt>
-  <dd>How to debug web apps using JavaScript Console APIs.</dd>
-  <dt><a href="{@docRoot}guide/webapps/best-practices.html"><strong>Best Practices for Web
-Apps</strong></a></dt>
-  <dd>A list of practices you should follow, in order to provide an effective web application on
-Android-powered devices.</dd>
-</dl>
-
diff --git a/docs/html/guide/webapps/targeting.jd b/docs/html/guide/webapps/targeting.jd
index 7410202..7e02340 100644
--- a/docs/html/guide/webapps/targeting.jd
+++ b/docs/html/guide/webapps/targeting.jd
@@ -1,16 +1,8 @@
-page.title=Targeting Screens from Web Apps
+page.title=Supporting Different Screens in Web Apps
 @jd:body
 
 <div id="qv-wrapper">
 <div id="qv">
-<h2>Quickview</h2>
-<ul>
-  <li>You can target your web page for different screens using viewport metadata, CSS, and
-JavaScript</li>
-  <li>Techniques in this document work for Android 2.0 and greater, and for web pages rendered
-in the default Android Browser and in a {@link android.webkit.WebView}</li>
-</ul>
-
 <h2>In this document</h2>
 <ol>
 <li><a href="#Metadata">Using Viewport Metadata</a>
@@ -24,78 +16,88 @@
 <li><a href="#DensityJS">targeting Device Density with JavaScript</a></li>
 </ol>
 
+<h2>See also</h2>
+<ul>
+  <li><a href="https://developers.google.com/chrome/mobile/docs/webview/pixelperfect"
+  >Pixel-Perfect UI in the WebView</a></li>
+  <li><a href="http://www.html5rocks.com/en/mobile/responsivedesign/" class="external-link">Creating
+  a Mobile-First Responsive Web Design</a></li>
+  <li><a href="http://www.html5rocks.com/en/mobile/high-dpi/" class="external-link">High
+  DPI Images for Variable Pixel Densities</a></li>
+</ul>
+
 </div>
 </div>
 
 
-<p>If you're developing a web application for Android or redesigning one for mobile devices, you
-should carefully consider how your web pages appear on different kinds of screens. Because
-Android is available on devices with different types of screens, you should account for some factors
-that affect the way your web pages appear on Android devices.</p>
+<p>Because Android is available on devices with a variety of screen sizes and pixel densities, you
+should account for these factors in your web design so your web pages always appear at the
+appropriate size.</p>
 
-<p class="note"><strong>Note:</strong> The features described in this document are supported
-by the Android Browser application (provided with the default Android platform) and {@link
-android.webkit.WebView} (the framework view widget for displaying web pages), on Android 2.0 and
-greater. Third-party web browsers running on Android might not support these features for
-controlling the viewport size and screen densities.</p>
 
-<p>When targeting your web pages for Android devices, there are two fundamental factors that you
+<p>When targeting your web pages for Android devices, there are two major factors that you
 should account for:</p>
 
 <dl>
-  <dt>The size of the viewport and scale of the web page</dt>
-    <dd>When the Android Browser loads a web page, the default behavior is to load the
-page in "overview mode," which provides a zoomed-out perspective of the web page. You can override
-this behavior for your web page by defining the default dimensions of the viewport or the initial
-scale of the viewport. You can also control how much the user can zoom in and out of your web
-page, if at all. The user can also disable overview mode in the
-Browser settings, so you should never assume that your page will load in overview mode. You
-should instead customize the viewport size and/or scale as appropriate for your page.</p>
-    <p>However, when your page is rendered in a {@link android.webkit.WebView}, the page loads at
-full zoom (not in "overview mode"). That is, it appears at the default size for the page,
-instead of zoomed out. (This is also how the page appears if the user disables overview
-mode.)</p></dd>
+  <dt><a href="#Viewport">The viewport</a></dt>
+    <dd>The viewport is the rectangular area that provides a drawable region for your web page.
+    You can specify several viewport properties, such as its size and initial scale. Most important
+    is the view port width, which defines the total number of horizontal pixels available from the web page's point of
+    view (the number of CSS pixels available).
+   </dd>
 
-  <dt>The device's screen density</dt>
-    <dd>The screen density (the number of pixels per inch) on an Android-powered device affects
-the resolution and size at which a web page is displayed. (There are three screen density
-categories: low, medium, and high.) The Android Browser and {@link android.webkit.WebView}
-compensate for variations in the screen
-density by scaling a web page so that all devices display the web page at the same perceivable size
-as a medium-density screen. If graphics are an important element of your web design, you
-should pay close attention to the scaling that occurs on different densities, because image scaling
-can produce artifacts (blurring and pixelation).
-      <p>To provide the best visual representation on all
-screen densities, you should control how scaling occurs by providing viewport metadata about
-your web page's target screen density and providing alternative graphics for different screen
-densities, which you can apply to different screens using CSS or JavaScript.</p></dd>
+  <dt><a href="#DensityCSS">The screen density</a></dt>
+<dd>The {@link android.webkit.WebView} class and most web browsers on Android convert your CSS
+pixel values to density-independent pixel values, so your web page appears at the same perceivable
+size as a medium-density screen (about 160dpi). However, if graphics are an important element of
+your web design, you should pay close attention to the scaling that occurs on different densities,
+because a 300px-wide image on a 320dpi screen will be scaled up (using more physical pixels per CSS
+pixel), which can produce artifacts (blurring and pixelation).</dd>
+
 </dl>
 
-<p>The rest of this document describes how you can account for these effects and provide a good
-design on multiple types of screens.</p>
 
 
 
-<h2 id="Metadata">Using Viewport Metadata</h2>
 
-<p>The viewport is the area in which your web page is drawn. Although the viewport's visible area
-matches the size of the screen,
-the viewport has its own dimensions that determine the number of pixels available to a web page.
-That is, the number of pixels available to a web page before it exceeds the screen area is
-defined by the dimensions of the viewport,
-not the dimensions of the device screen. For example, although a device screen might have a width of
-480 pixels, the viewport can have a width of 800 pixels, so that a web page designed to be 800
-pixels wide is completely visible on the screen.</p>
+<h2 id="Viewport">Specifying Viewport Properties</h2>
 
-<p>You can define properties of the viewport for your web page using the {@code "viewport"}
-property in an HTML {@code &lt;meta&gt;} tag (which must
-be placed in your document {@code &lt;head&gt;}). You can define multiple viewport properties in the
-{@code &lt;meta&gt;} tag's {@code content} attribute. For example, you can define the height and
-width of the viewport, the initial scale of the page, and the target screen density.
-Each viewport property in the {@code content} attribute must be separated by a comma.</p>
+<p>The viewport is the area in which your web page is drawn. Although the viewport's total visible
+area matches the size of the screen when zoomed all the way out, the viewport has its own pixel
+dimensions that it makes available to a web page. For example, although a device screen might
+have physical a width
+of 480 pixels, the viewport can have a width of 800 pixels. This allows a web page designed at 800
+pixels wide to be completely visible on the screen when the viewport scale is 1.0. Most web browsers on
+Android (including Chrome) set the viewport to a large size by default (known as "wide viewport
+mode" at about 980px wide). Many browsers also zoom out as far as possible, by default, to
+show the full viewport width (known as "overview mode").</p>
 
-<p>For example, the following snippet from an HTML document specifies that the viewport width
-should exactly match the device screen width and that the ability to zoom should be disabled:</p>
+<p class="note"><strong>Note:</strong>
+When your page is rendered in a {@link android.webkit.WebView}, it does not use wide viewport mode
+(the page appears at full zoom) by default. You can enable wide viewport mode
+with {@link android.webkit.WebSettings#setUseWideViewPort setUseWideViewPort()}.</p>
+
+<p>You can define properties of the viewport for your web page, such as the width and initial zoom
+level, using the {@code &lt;meta name="viewport" ...>} tag in your document
+{@code &lt;head&gt;}.</p>
+
+<p>The following syntax shows all of the
+supported viewport properties and the types of values accepted by each one:</p>
+
+<pre>
+&lt;meta name="viewport"
+      content="
+          <b>height</b> = [<em>pixel_value</em> | "device-height"] ,
+          <b>width</b> = [<em>pixel_value</em> | "device-width"] ,
+          <b>initial-scale</b> = <em>float_value</em> ,
+          <b>minimum-scale</b> = <em>float_value</em> ,
+          <b>maximum-scale</b> = <em>float_value</em> ,
+          <b>user-scalable</b> = ["yes" | "no"]
+          " /&gt;
+</pre>
+
+<p>For example, the following {@code &lt;meta&gt;} tag specifies that the viewport width
+should exactly match the device screen's width and that the ability to zoom should be disabled:</p>
 
 <pre>
 &lt;head&gt;
@@ -104,235 +106,17 @@
 &lt;/head&gt;
 </pre>
 
-<p>That's an example of just two viewport properties. The following syntax shows all of the
-supported viewport properties and the general types of values accepted by each one:</p>
 
-<pre>
-&lt;meta name="viewport"
-      content="
-          <b>height</b> = [<em>pixel_value</em> | device-height] ,
-          <b>width</b> = [<em>pixel_value</em> | device-width ] ,
-          <b>initial-scale</b> = <em>float_value</em> ,
-          <b>minimum-scale</b> = <em>float_value</em> ,
-          <b>maximum-scale</b> = <em>float_value</em> ,
-          <b>user-scalable</b> = [yes | no] ,
-          <b>target-densitydpi</b> = [<em>dpi_value</em> | device-dpi |
-                               high-dpi | medium-dpi | low-dpi]
-          " /&gt;
-</pre>
+<p>When optimizing your site for mobile devices, you should usually set the width to
+{@code "device-width"} so the size fits exactly on all devices, then use CSS media queries to 
+flexibly adapt layouts to suit different screen sizes.
 
-<p>The following sections discuss how to use each of these viewport properties and exactly what the
-accepted values are.</p>
-
-<div class="figure" style="width:300px">
-  <img src="{@docRoot}images/webapps/compare-default.png" alt="" height="300" />
-  <p class="img-caption"><strong>Figure 1.</strong> A web page with an image that's 320 pixels
-wide, in the Android Browser when there is no viewport metadata set (with "overview mode"
-enabled, the viewport is 800 pixels wide, by default).</p>
-</div>
-
-
-<div class="figure" style="width:300px">
-  <img src="{@docRoot}images/webapps/compare-width400.png" alt="" height="300" />
-  <p class="img-caption"><strong>Figure 2.</strong> A web page with viewport {@code width=400} and
-"overview mode" enabled (the image in the web page is 320 pixels wide).</p>
-</div>
-
-
-<h3 id="ViewportSize">Defining the viewport size</h3>
-
-<p>Viewport's {@code height} and {@code width} properties allow you to specify the size of the
-viewport (the number of pixels available to the web page before it goes off screen).</p>
-
-<p>As mentioned in the introduction above, the Android Browser loads pages in "overview mode" by
-default (unless disable by the user), which sets the minimum viewport width to 800 pixels. So, if
-your web page specifies its size to be 320 pixels wide, then your page appears smaller than the
-visible screen (even if the physical screen is 320 pixels wide, because the viewport simulates a
-drawable area that's 800 pixels wide), as shown in figure 1. To avoid this effect, you should
-explicitly define the viewport {@code width} to match the width for which you have designed your web
-page.</p>
-
-<p>For example, if your web page is designed to be exactly 320 pixels wide, then you might
-want to specify that size for the viewport width:</p>
-
-<pre>
-&lt;meta name="viewport" content="width=320" /&gt;
-</pre>
-
-<p>In this case, your web page exactly fits the screen width, because the web page width and
-viewport width are the same.</p>
-
-<p class="note"><strong>Note:</strong> Width values that are greater than 10,000 are ignored and
-values less than (or equal to) 320 result in a value equal to the device-width (discussed below).
-Height values that are greater then 10,000 or less than 200 are also ignored.</p>
-
-<p>To demonstrate how this property affects the size of
-your web page, figure 2 shows a web page that contains an image that's 320 pixels
-wide, but with the viewport width set to 400.</p>
-
-
-<p class="note"><strong>Note:</strong> If you set the viewport width to match your web page width
-and the device's screen width does <em>not</em> match those dimensions, then the web page
-still fits the screen even if the device has a high or low-density screen, because the
-Android Browser and {@link android.webkit.WebView} scale web pages to match the perceived size on a
-medium-density screen, by default (as you can see in figure 2, when comparing the hdpi device to the
-mdpi device). Screen densities are discussed more in <a href="#ViewportDensity">Defining the
-viewport target density</a>.</p>
-
-
-<h4>Automatic sizing</h4>
-
-<p>As an alternative to specifying the viewport dimensions with exact pixels, you can set the
-viewport size to always match the dimensions of the device screen, by defining the
-viewport properties {@code height}
-and {@code width} with the values {@code device-height} and {@code device-width}, respectively. This
-is appropriate when you're developing a web application that has a fluid width (not fixed width),
-but you want it to appear as if it's fixed (to perfectly fit every screen as
-if the web page width is set to match each screen). For example:</p>
-
-<pre>
-&lt;meta name="viewport" content="width=device-width" /&gt;
-</pre>
-
-<p>This results in the viewport width matching whatever the current screen width is, as shown in
-figure 3. It's important to notice that, this results in images being scaled to fit the screen
-when the current device does not match the <a href="#ViewportDensity">target
-density</a>, which is medium-density if you don't specify otherwise. As a result, the image
-displayed on the high-density device in figure 3 is scaled up in order to match the width
-of a screen with a medium-density screen.</p>
-
-<div class="figure" style="width:300px">
-  <img src="{@docRoot}images/webapps/compare-initialscale.png" alt="" height="300" />
-  <p class="img-caption"><strong>Figure 3.</strong> A web page with viewport {@code
-width=device-width} <em>or</em> {@code initial-scale=1.0}.</p>
-</div>
-
-<p class="note"><strong>Note:</strong> If you instead want {@code
-device-width} and {@code device-height} to match the physical screen pixels for every device,
-instead of scaling your web page to match the target density, then you must also include
-the {@code target-densitydpi} property with a value of {@code device-dpi}. This is discussed more in
-the section about <a href="#ViewportDensity">Defining the viewport density</a>. Otherwise, simply
-using {@code device-height} and {@code device-width} to define the viewport size makes your web page
-fit every device screen, but scaling occurs on your images in order to adjust for different screen
-densities.</p>
-
-
-
-<h3 id="ViewportScale">Defining the viewport scale</h3>
-
-<p>The scale of the viewport defines the level of zoom applied to the web page. Viewport
-properties allow you to specify the scale of your web page in the following ways:</p>
-<dl>
-  <dt>{@code initial-scale}</dt>
-  <dd>The initial scale of the page. The value is a float that indicates a multiplier for your web
-page size, relative to the screen size. For example, if you set the initial scale to "1.0" then the
-web page is displayed to match the resolution of the <a href="#ViewportDensity">target
-density</a> 1-to-1. If set to "2.0", then the page is enlarged (zoomed in) by a factor of 2.
-    <p>The default initial scale is calculated to fit the web page in the viewport size.
-Because the default viewport width is 800 pixels, if the device screen resolution is less than
-800 pixels wide, the initial scale is something less than 1.0, by default, in order to fit the
-800-pixel-wide page on the screen.</p></dd>
-
-  <dt>{@code minimum-scale}</dt>
-  <dd>The minimum scale to allow. The value is a float that indicates the minimum multiplier for
-your web page size, relative to the screen size. For example, if you set this to "1.0", then the
-page can't zoom out because the minimum size is 1-to-1 with the <a href="#ViewportDensity">target
-density</a>.</dd>
-
-  <dt>{@code maximum-scale}</dt>
-  <dd>The maximum scale to allow for the page. The value is a float that indicates the
-maximum multiplier for your web page size,
-relative to the screen size. For example, if you set this to "2.0", then the page can't
-zoom in more than 2 times the target size.</dd>
-
-  <dt>{@code user-scalable}</dt>
-  <dd>Whether the user can change the scale of the page at all (zoom in and out). Set to {@code yes}
-to allow scaling and {@code no} to disallow scaling. The default is {@code yes}. If you set
-this to {@code no}, then the {@code minimum-scale} and {@code maximum-scale} are ignored,
-because scaling is not possible.</dd>
-</dl>
-
-<p>All scale values must be within the range 0.01&ndash;10.</p>
-
-<p>For example:</p>
-
-<pre>
-&lt;meta name="viewport" content="initial-scale=1.0" /&gt;
-</pre>
-
-<p>This metadata sets the initial scale to be full sized, relative to the viewport's target
-density.</p>
+<p class="note"><strong>Note:</strong> You should disable user scaling only when you're certain
+that your web page layout is flexible and the content will fit the width of small screens.</p>
 
 
 
 
-<h3 id="ViewportDensity">Defining the viewport target density</h3>
-
-<p>The density of a device's screen is based on the screen resolution, as defined by the number of
-dots per inch (dpi). There are three screen
-density categories supported by Android: low (ldpi), medium (mdpi), and high (hdpi). A screen
-with low density has fewer available pixels per inch, whereas a screen with high density has more
-pixels per inch (compared to a medium density screen). The Android Browser and {@link
-android.webkit.WebView} target a medium density screen by default.</p>
-
-
-<div class="figure" style="width:300px">
-  <img src="{@docRoot}images/webapps/compare-initialscale-devicedpi.png" alt="" height="300" />
-  <p class="img-caption"><strong>Figure 4.</strong> A web page with viewport {@code
-width=device-width} and {@code target-densitydpi=device-dpi}.</p>
-</div>
-
-
-<p>Because the default target density is medium, when users have a device with a low or high density
-screen, the Android Browser and {@link android.webkit.WebView} scale web pages (effectively zoom
-the pages) so they display at a
-size that matches the perceived appearance on a medium density screen. More specifically, the
-Android Browser and {@link android.webkit.WebView} apply approximately 1.5x scaling to web pages
-on a high density screen (because its screen pixels are smaller) and approximately 0.75x scaling to
-pages on a low density screen (because its screen pixels are bigger).</p>
-
-<p>Due to this default scaling, figures 1, 2, and 3 show the example web page at the same physical
-size on both the high and medium density device (the high-density device shows the
-web page with a default scale factor that is 1.5 times larger than the actual pixel resolution, to
-match the target density). This can introduce some undesirable artifacts in your images.
-For example, although an image appears the same size on a medium and high-density device, the image
-on the high-density device appears more blurry, because the image is designed to be 320 pixels
-wide, but is drawn with 480 pixels.</p>
-
-<p>You can change the target screen density for your web page using the {@code target-densitydpi}
-viewport property. It accepts the following values:</p>
-
-<ul>
-<li><code>device-dpi</code> - Use the device's native dpi as the target dpi. Default scaling never
-occurs.</li>
-<li><code>high-dpi</code> - Use hdpi as the target dpi. Medium and low density screens scale down
-as appropriate.</li>
-<li><code>medium-dpi</code> - Use mdpi as the target dpi. High density screens scale up and low
-density screens scale down. This is the default target density.</li>
-<li><code>low-dpi</code> - Use ldpi as the target dpi. Medium and high density screens scale up
-as appropriate.</li>
-<li><em><code>&lt;value&gt;</code></em> - Specify a dpi value to use as the target dpi. Values must
-be within the range 70&ndash;400.</li>
-</ul></p>
-
-<p>For example, to prevent the Android Browser and {@link android.webkit.WebView} from scaling
-your web page for different screen densities, set
-the {@code target-densitydpi} viewport property to {@code device-dpi}. When you do, the page is
-not scaled. Instead, the page is displayed at a size that matches the current screen's
-density. In this case, you should also define the viewport width to match the device width, so your
-web page naturally fits the screen size. For example:</p>
-
-<pre>
-&lt;meta name="viewport" content="target-densitydpi=device-dpi, width=device-width" /&gt;
-</pre>
-
-<p>Figure 4 shows a web page using these viewport settings&mdash;the high-density device
-now displays the page smaller because its physical pixels are smaller than those on the
-medium-density device, so no scaling occurs and the 320-pixel-wide image is drawn using exactly 320
-pixels on both screens. (This is how you should define your viewport if
-you want to customize your web page based on screen density and provide different image assets for
-different densities, <a href="#DensityCSS">with CSS</a> or
-<a href="#DensityJS">with JavaScript</a>.)</p>
 
 
 <h2 id="DensityCSS">Targeting Device Density with CSS</h2>
@@ -349,17 +133,9 @@
 <pre>
 &lt;link rel="stylesheet" media="screen and (-webkit-device-pixel-ratio: 1.5)" href="hdpi.css" /&gt;
 &lt;link rel="stylesheet" media="screen and (-webkit-device-pixel-ratio: 1.0)" href="mdpi.css" /&gt;
-&lt;link rel="stylesheet" media="screen and (-webkit-device-pixel-ratio: 0.75)" href="ldpi.css" /&gt;
 </pre>
 
 
-<div class="figure" style="width:300px">
-  <img src="{@docRoot}images/webapps/compare-width-devicedpi-css.png" alt="" height="300" />
-  <p class="img-caption"><strong>Figure 5.</strong> A web page with CSS that's targetted to
-specific screen densities using the {@code -webkit-device-pixel-ratio} media feature. Notice
-that the hdpi device shows a different image that's applied in CSS.</p>
-</div>
-
 <p>Or, specify the different styles in one stylesheet:</p>
 
 <pre class="no-pretty-print">
@@ -382,27 +158,10 @@
 }
 </pre>
 
-<p class="note"><strong>Note:</strong> The default style for {@code #header} applies the image
-designed for medium-density devices in order to support devices running a version of Android less
-than 2.0, which do not support the {@code -webkit-device-pixel-ratio} media feature.</p>
 
-<p>The types of styles you might want to adjust based on the screen density depend on how you've
-defined your viewport properties. To provide fully-customized styles that tailor your web page for
-each of the supported densities, you should set your viewport properties so the viewport width and
-density match the device. That is:</p>
-
-<pre>
-&lt;meta name="viewport" content="target-densitydpi=device-dpi, width=device-width" /&gt;
-</pre>
-
-<p>This way, the Android Browser and {@link android.webkit.WebView} do not perform scaling on your
-web page and the viewport width
-matches the screen width exactly. On their own, these viewport properties create results shown in
-figure 4. However, by adding some custom CSS using the {@code -webkit-device-pixel-ratio} media
-feature, you can apply different styles. For example, figure 5 shows a web page with these viewport
-properties and also some CSS added that applies a high-resolution image for high-density
-screens.</p>
-
+<p>For more information about handling different screen densities, especially images, see
+<a href="http://www.html5rocks.com/en/mobile/high-dpi/" class="external-link">High
+  DPI Images for Variable Pixel Densities</a>.</li>
 
 
 <h2 id="DensityJS">Targeting Device Density with JavaScript</h2>
@@ -432,8 +191,3 @@
 </pre>
 
 
-
-
-
-
-
diff --git a/docs/html/guide/webapps/webview.jd b/docs/html/guide/webapps/webview.jd
index c87be06..9b46b5b 100644
--- a/docs/html/guide/webapps/webview.jd
+++ b/docs/html/guide/webapps/webview.jd
@@ -136,7 +136,6 @@
 setUserAgentString()}, then query the custom user agent in your web page to verify that the
 client requesting your web page is actually your Android application.</p>
 
-from your Android SDK {@code tools/} directory
 <h3 id="BindingJavaScript">Binding JavaScript code to Android code</h3>
 
 <p>When developing a web application that's designed specifically for the {@link
diff --git a/docs/html/images/gcm/CCS-ack.png b/docs/html/images/gcm/CCS-ack.png
new file mode 100644
index 0000000..bce2ab2
--- /dev/null
+++ b/docs/html/images/gcm/CCS-ack.png
Binary files differ
diff --git a/docs/html/images/gcm/GCM-arch.png b/docs/html/images/gcm/GCM-arch.png
new file mode 100644
index 0000000..e8ffb15
--- /dev/null
+++ b/docs/html/images/gcm/GCM-arch.png
Binary files differ
diff --git a/docs/html/images/tools/sync-project.png b/docs/html/images/tools/sync-project.png
new file mode 100644
index 0000000..09e1835
--- /dev/null
+++ b/docs/html/images/tools/sync-project.png
Binary files differ
diff --git a/docs/html/images/webapps/web-viewport-320@2x.png b/docs/html/images/webapps/web-viewport-320@2x.png
new file mode 100644
index 0000000..f6b2bac
--- /dev/null
+++ b/docs/html/images/webapps/web-viewport-320@2x.png
Binary files differ
diff --git a/docs/html/images/webapps/web-viewport-default@2x.png b/docs/html/images/webapps/web-viewport-default@2x.png
new file mode 100644
index 0000000..a3f8d53
--- /dev/null
+++ b/docs/html/images/webapps/web-viewport-default@2x.png
Binary files differ
diff --git a/docs/html/images/webapps/web-viewport-devicewidth@2x.png b/docs/html/images/webapps/web-viewport-devicewidth@2x.png
new file mode 100644
index 0000000..3832f4c
--- /dev/null
+++ b/docs/html/images/webapps/web-viewport-devicewidth@2x.png
Binary files differ
diff --git a/docs/html/samples/samples_toc.cs b/docs/html/samples/samples_toc.cs
index 7ad8433..18f7034 100644
--- a/docs/html/samples/samples_toc.cs
+++ b/docs/html/samples/samples_toc.cs
@@ -14,5 +14,5 @@
   </li>
 
 
-  <li class="nav-section"><div class="nav-section-header"><a href="/samples/background.html" title="Background">Background</a></div><ul><li class="nav-section"><div class="nav-section-header"><a href="/samples/repeatingAlarm/index.html" title="repeatingAlarm">repeatingAlarm</a></div><ul><li><a href="/samples/repeatingAlarm/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/repeatingAlarm/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/repeatingAlarm/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/repeatingAlarm/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/repeatingAlarm/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/repeatingAlarm/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/repeatingAlarm/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/repeatingAlarm/res/menu/main.html" title="main.xml">main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/repeatingAlarm/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/repeatingAlarm/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/repeatingAlarm/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/repeatingAlarm/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/repeatingAlarm/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/repeatingAlarm/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common">com.example.android.common/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="activities">activities/</a></div><ul><li><a href="/samples/repeatingAlarm/src/com.example.android.common/activities/SampleActivityBase.html" title="SampleActivityBase.java">SampleActivityBase.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="logger">logger/</a></div><ul><li><a href="/samples/repeatingAlarm/src/com.example.android.common/logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/repeatingAlarm/src/com.example.android.common/logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/repeatingAlarm/src/com.example.android.common/logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/repeatingAlarm/src/com.example.android.common/logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/repeatingAlarm/src/com.example.android.common/logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/repeatingAlarm/src/com.example.android.common/logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.repeatingalarm">com.example.android.repeatingalarm/</a></div><ul><li><a href="/samples/repeatingAlarm/src/com.example.android.repeatingalarm/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li><li><a href="/samples/repeatingAlarm/src/com.example.android.repeatingalarm/RepeatingAlarmFragment.html" title="RepeatingAlarmFragment.java">RepeatingAlarmFragment.java</a></li></ul></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/connectivity.html" title="Connectivity">Connectivity</a></div><ul><li class="nav-section"><div class="nav-section-header"><a href="/samples/BluetoothLeGatt/index.html" title="BluetoothLeGatt">BluetoothLeGatt</a></div><ul><li><a href="/samples/BluetoothLeGatt/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/BluetoothLeGatt/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/BluetoothLeGatt/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/BluetoothLeGatt/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/BluetoothLeGatt/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/BluetoothLeGatt/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/BluetoothLeGatt/res/layout/actionbar_indeterminate_progress.html" title="actionbar_indeterminate_progress.xml">actionbar_indeterminate_progress.xml</a></li><li><a href="/samples/BluetoothLeGatt/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/BluetoothLeGatt/res/layout/gatt_services_characteristics.html" title="gatt_services_characteristics.xml">gatt_services_characteristics.xml</a></li><li><a href="/samples/BluetoothLeGatt/res/layout/listitem_device.html" title="listitem_device.xml">listitem_device.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/BluetoothLeGatt/res/menu/gatt_services.html" title="gatt_services.xml">gatt_services.xml</a></li><li><a href="/samples/BluetoothLeGatt/res/menu/main.html" title="main.xml">main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/BluetoothLeGatt/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/BluetoothLeGatt/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BluetoothLeGatt/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/BluetoothLeGatt/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/BluetoothLeGatt/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BluetoothLeGatt/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.bluetoothlegatt">com.example.android.bluetoothlegatt/</a></div><ul><li><a href="/samples/BluetoothLeGatt/src/com.example.android.bluetoothlegatt/BluetoothLeService.html" title="BluetoothLeService.java">BluetoothLeService.java</a></li><li><a href="/samples/BluetoothLeGatt/src/com.example.android.bluetoothlegatt/DeviceControlActivity.html" title="DeviceControlActivity.java">DeviceControlActivity.java</a></li><li><a href="/samples/BluetoothLeGatt/src/com.example.android.bluetoothlegatt/DeviceScanActivity.html" title="DeviceScanActivity.java">DeviceScanActivity.java</a></li><li><a href="/samples/BluetoothLeGatt/src/com.example.android.bluetoothlegatt/SampleGattAttributes.html" title="SampleGattAttributes.java">SampleGattAttributes.java</a></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/NetworkConnect/index.html" title="NetworkConnect">NetworkConnect</a></div><ul><li><a href="/samples/NetworkConnect/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/NetworkConnect/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/NetworkConnect/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/NetworkConnect/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/NetworkConnect/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/NetworkConnect/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/NetworkConnect/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/NetworkConnect/res/layout/sample_main.html" title="sample_main.xml">sample_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/NetworkConnect/res/menu/main.html" title="main.xml">main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/NetworkConnect/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/NetworkConnect/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/NetworkConnect/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/NetworkConnect/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/NetworkConnect/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/NetworkConnect/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common.logger">com.example.android.common.logger/</a></div><ul><li><a href="/samples/NetworkConnect/src/com.example.android.common.logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/NetworkConnect/src/com.example.android.common.logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/NetworkConnect/src/com.example.android.common.logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/NetworkConnect/src/com.example.android.common.logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/NetworkConnect/src/com.example.android.common.logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/NetworkConnect/src/com.example.android.common.logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.networkconnect">com.example.android.networkconnect/</a></div><ul><li><a href="/samples/NetworkConnect/src/com.example.android.networkconnect/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li><li><a href="/samples/NetworkConnect/src/com.example.android.networkconnect/SimpleTextFragment.html" title="SimpleTextFragment.java">SimpleTextFragment.java</a></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/BasicNetworking/index.html" title="BasicNetworking">BasicNetworking</a></div><ul><li><a href="/samples/BasicNetworking/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/BasicNetworking/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/BasicNetworking/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/BasicNetworking/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/BasicNetworking/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/BasicNetworking/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/BasicNetworking/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/BasicNetworking/res/layout/sample_main.html" title="sample_main.xml">sample_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/BasicNetworking/res/menu/main.html" title="main.xml">main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/BasicNetworking/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/BasicNetworking/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicNetworking/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/BasicNetworking/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/BasicNetworking/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicNetworking/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.basicnetworking">com.example.android.basicnetworking/</a></div><ul><li><a href="/samples/BasicNetworking/src/com.example.android.basicnetworking/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li><li><a href="/samples/BasicNetworking/src/com.example.android.basicnetworking/SimpleTextFragment.html" title="SimpleTextFragment.java">SimpleTextFragment.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common.logger">com.example.android.common.logger/</a></div><ul><li><a href="/samples/BasicNetworking/src/com.example.android.common.logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/BasicNetworking/src/com.example.android.common.logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/BasicNetworking/src/com.example.android.common.logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/BasicNetworking/src/com.example.android.common.logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/BasicNetworking/src/com.example.android.common.logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/BasicNetworking/src/com.example.android.common.logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/BasicSyncAdapter/index.html" title="BasicSyncAdapter">BasicSyncAdapter</a></div><ul><li><a href="/samples/BasicSyncAdapter/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/BasicSyncAdapter/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/BasicSyncAdapter/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/BasicSyncAdapter/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/BasicSyncAdapter/res/drawable-xhdpi/ic_action_refresh.html" title="ic_action_refresh.png">ic_action_refresh.png</a></li><li><a href="/samples/BasicSyncAdapter/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/BasicSyncAdapter/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/BasicSyncAdapter/res/layout/actionbar_indeterminate_progress.html" title="actionbar_indeterminate_progress.xml">actionbar_indeterminate_progress.xml</a></li><li><a href="/samples/BasicSyncAdapter/res/layout/activity_entry_list.html" title="activity_entry_list.xml">activity_entry_list.xml</a></li><li><a href="/samples/BasicSyncAdapter/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/BasicSyncAdapter/res/menu/main.html" title="main.xml">main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/BasicSyncAdapter/res/values/attrs.html" title="attrs.xml">attrs.xml</a></li><li><a href="/samples/BasicSyncAdapter/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/BasicSyncAdapter/res/values/dimen.html" title="dimen.xml">dimen.xml</a></li><li><a href="/samples/BasicSyncAdapter/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicSyncAdapter/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/BasicSyncAdapter/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/BasicSyncAdapter/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicSyncAdapter/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="xml">xml/</a></div><ul><li><a href="/samples/BasicSyncAdapter/res/xml/authenticator.html" title="authenticator.xml">authenticator.xml</a></li><li><a href="/samples/BasicSyncAdapter/res/xml/syncadapter.html" title="syncadapter.xml">syncadapter.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.basicsyncadapter">com.example.android.basicsyncadapter/</a></div><ul><li><a href="/samples/BasicSyncAdapter/src/com.example.android.basicsyncadapter/EntryListActivity.html" title="EntryListActivity.java">EntryListActivity.java</a></li><li><a href="/samples/BasicSyncAdapter/src/com.example.android.basicsyncadapter/EntryListFragment.html" title="EntryListFragment.java">EntryListFragment.java</a></li><li><a href="/samples/BasicSyncAdapter/src/com.example.android.basicsyncadapter/SyncAdapter.html" title="SyncAdapter.java">SyncAdapter.java</a></li><li><a href="/samples/BasicSyncAdapter/src/com.example.android.basicsyncadapter/SyncService.html" title="SyncService.java">SyncService.java</a></li><li><a href="/samples/BasicSyncAdapter/src/com.example.android.basicsyncadapter/SyncUtils.html" title="SyncUtils.java">SyncUtils.java</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="net">net/</a></div><ul><li><a href="/samples/BasicSyncAdapter/src/com.example.android.basicsyncadapter/net/FeedParser.html" title="FeedParser.java">FeedParser.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="provider">provider/</a></div><ul><li><a href="/samples/BasicSyncAdapter/src/com.example.android.basicsyncadapter/provider/FeedContract.html" title="FeedContract.java">FeedContract.java</a></li><li><a href="/samples/BasicSyncAdapter/src/com.example.android.basicsyncadapter/provider/FeedProvider.html" title="FeedProvider.java">FeedProvider.java</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common">com.example.android.common/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="accounts">accounts/</a></div><ul><li><a href="/samples/BasicSyncAdapter/src/com.example.android.common/accounts/GenericAccountService.html" title="GenericAccountService.java">GenericAccountService.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="db">db/</a></div><ul><li><a href="/samples/BasicSyncAdapter/src/com.example.android.common/db/SelectionBuilder.html" title="SelectionBuilder.java">SelectionBuilder.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="logger">logger/</a></div><ul><li><a href="/samples/BasicSyncAdapter/src/com.example.android.common/logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/BasicSyncAdapter/src/com.example.android.common/logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/BasicSyncAdapter/src/com.example.android.common/logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/BasicSyncAdapter/src/com.example.android.common/logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/BasicSyncAdapter/src/com.example.android.common/logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/BasicSyncAdapter/src/com.example.android.common/logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li></ul></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/content.html" title="Content">Content</a></div><ul><li class="nav-section"><div class="nav-section-header"><a href="/samples/BasicContactables/index.html" title="BasicContactables">BasicContactables</a></div><ul><li><a href="/samples/BasicContactables/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/BasicContactables/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/BasicContactables/res/drawable-hdpi/ic_search_api_holo_light.html" title="ic_search_api_holo_light.png">ic_search_api_holo_light.png</a></li><li><a href="/samples/BasicContactables/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/BasicContactables/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/BasicContactables/res/drawable-mdpi/ic_search_api_holo_light.html" title="ic_search_api_holo_light.png">ic_search_api_holo_light.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/BasicContactables/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/BasicContactables/res/drawable-xhdpi/ic_search_api_holo_light.html" title="ic_search_api_holo_light.png">ic_search_api_holo_light.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/BasicContactables/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/BasicContactables/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/BasicContactables/res/layout/sample_main.html" title="sample_main.xml">sample_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/BasicContactables/res/menu/main.html" title="main.xml">main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/BasicContactables/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/BasicContactables/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicContactables/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/BasicContactables/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/BasicContactables/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicContactables/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="xml">xml/</a></div><ul><li><a href="/samples/BasicContactables/res/xml/searchable.html" title="searchable.xml">searchable.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.basiccontactables">com.example.android.basiccontactables/</a></div><ul><li><a href="/samples/BasicContactables/src/com.example.android.basiccontactables/ContactablesLoaderCallbacks.html" title="ContactablesLoaderCallbacks.java">ContactablesLoaderCallbacks.java</a></li><li><a href="/samples/BasicContactables/src/com.example.android.basiccontactables/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common.logger">com.example.android.common.logger/</a></div><ul><li><a href="/samples/BasicContactables/src/com.example.android.common.logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/BasicContactables/src/com.example.android.common.logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/BasicContactables/src/com.example.android.common.logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/BasicContactables/src/com.example.android.common.logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/BasicContactables/src/com.example.android.common.logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/BasicContactables/src/com.example.android.common.logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/AppRestrictions/index.html" title="AppRestrictions">AppRestrictions</a></div><ul><li><a href="/samples/AppRestrictions/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/AppRestrictions/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/AppRestrictions/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/AppRestrictions/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/AppRestrictions/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/AppRestrictions/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/AppRestrictions/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/AppRestrictions/res/layout/main.html" title="main.xml">main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/AppRestrictions/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/AppRestrictions/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/AppRestrictions/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/AppRestrictions/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/AppRestrictions/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/AppRestrictions/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="xml">xml/</a></div><ul><li><a href="/samples/AppRestrictions/res/xml/custom_prefs.html" title="custom_prefs.xml">custom_prefs.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.apprestrictions">com.example.android.apprestrictions/</a></div><ul><li><a href="/samples/AppRestrictions/src/com.example.android.apprestrictions/CustomRestrictionsActivity.html" title="CustomRestrictionsActivity.java">CustomRestrictionsActivity.java</a></li><li><a href="/samples/AppRestrictions/src/com.example.android.apprestrictions/CustomRestrictionsFragment.html" title="CustomRestrictionsFragment.java">CustomRestrictionsFragment.java</a></li><li><a href="/samples/AppRestrictions/src/com.example.android.apprestrictions/GetRestrictionsReceiver.html" title="GetRestrictionsReceiver.java">GetRestrictionsReceiver.java</a></li><li><a href="/samples/AppRestrictions/src/com.example.android.apprestrictions/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/StorageClient/index.html" title="StorageClient">StorageClient</a></div><ul><li><a href="/samples/StorageClient/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/StorageClient/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/StorageClient/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/StorageClient/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/StorageClient/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/StorageClient/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/StorageClient/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/StorageClient/res/menu/main.html" title="main.xml">main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/StorageClient/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/StorageClient/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/StorageClient/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/StorageClient/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/StorageClient/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/StorageClient/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common">com.example.android.common/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="activities">activities/</a></div><ul><li><a href="/samples/StorageClient/src/com.example.android.common/activities/SampleActivityBase.html" title="SampleActivityBase.java">SampleActivityBase.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="logger">logger/</a></div><ul><li><a href="/samples/StorageClient/src/com.example.android.common/logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/StorageClient/src/com.example.android.common/logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/StorageClient/src/com.example.android.common/logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/StorageClient/src/com.example.android.common/logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/StorageClient/src/com.example.android.common/logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/StorageClient/src/com.example.android.common/logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.storageclient">com.example.android.storageclient/</a></div><ul><li><a href="/samples/StorageClient/src/com.example.android.storageclient/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li><li><a href="/samples/StorageClient/src/com.example.android.storageclient/StorageClientFragment.html" title="StorageClientFragment.java">StorageClientFragment.java</a></li></ul></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/input.html" title="Input">Input</a></div><ul><li class="nav-section"><div class="nav-section-header"><a href="/samples/BasicMultitouch/index.html" title="BasicMultitouch">BasicMultitouch</a></div><ul><li><a href="/samples/BasicMultitouch/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/BasicMultitouch/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/BasicMultitouch/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/BasicMultitouch/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/BasicMultitouch/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/BasicMultitouch/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/BasicMultitouch/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/BasicMultitouch/res/layout/layout_mainactivity.html" title="layout_mainactivity.xml">layout_mainactivity.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/BasicMultitouch/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/BasicMultitouch/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicMultitouch/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/BasicMultitouch/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/BasicMultitouch/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicMultitouch/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-v11">values-v11/</a></div><ul><li><a href="/samples/BasicMultitouch/res/values-v11/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-v14">values-v14/</a></div><ul><li><a href="/samples/BasicMultitouch/res/values-v14/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.basicmultitouch">com.example.android.basicmultitouch/</a></div><ul><li><a href="/samples/BasicMultitouch/src/com.example.android.basicmultitouch/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li><li><a href="/samples/BasicMultitouch/src/com.example.android.basicmultitouch/Pools.html" title="Pools.java">Pools.java</a></li><li><a href="/samples/BasicMultitouch/src/com.example.android.basicmultitouch/TouchDisplayView.html" title="TouchDisplayView.java">TouchDisplayView.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common.logger">com.example.android.common.logger/</a></div><ul><li><a href="/samples/BasicMultitouch/src/com.example.android.common.logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/BasicMultitouch/src/com.example.android.common.logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/BasicMultitouch/src/com.example.android.common.logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/BasicMultitouch/src/com.example.android.common.logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/BasicMultitouch/src/com.example.android.common.logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/BasicMultitouch/src/com.example.android.common.logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/BasicGestureDetect/index.html" title="BasicGestureDetect">BasicGestureDetect</a></div><ul><li><a href="/samples/BasicGestureDetect/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/BasicGestureDetect/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/BasicGestureDetect/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/BasicGestureDetect/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/BasicGestureDetect/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/BasicGestureDetect/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/BasicGestureDetect/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/BasicGestureDetect/res/menu/main.html" title="main.xml">main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/BasicGestureDetect/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/BasicGestureDetect/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicGestureDetect/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/BasicGestureDetect/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/BasicGestureDetect/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicGestureDetect/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.basicgesturedetect">com.example.android.basicgesturedetect/</a></div><ul><li><a href="/samples/BasicGestureDetect/src/com.example.android.basicgesturedetect/BasicGestureDetectFragment.html" title="BasicGestureDetectFragment.java">BasicGestureDetectFragment.java</a></li><li><a href="/samples/BasicGestureDetect/src/com.example.android.basicgesturedetect/GestureListener.html" title="GestureListener.java">GestureListener.java</a></li><li><a href="/samples/BasicGestureDetect/src/com.example.android.basicgesturedetect/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common">com.example.android.common/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="activities">activities/</a></div><ul><li><a href="/samples/BasicGestureDetect/src/com.example.android.common/activities/SampleActivityBase.html" title="SampleActivityBase.java">SampleActivityBase.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="logger">logger/</a></div><ul><li><a href="/samples/BasicGestureDetect/src/com.example.android.common/logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/BasicGestureDetect/src/com.example.android.common/logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/BasicGestureDetect/src/com.example.android.common/logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/BasicGestureDetect/src/com.example.android.common/logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/BasicGestureDetect/src/com.example.android.common/logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/BasicGestureDetect/src/com.example.android.common/logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li></ul></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/media.html" title="Media">Media</a></div><ul><li class="nav-section"><div class="nav-section-header"><a href="/samples/BasicMediaRouter/index.html" title="BasicMediaRouter">BasicMediaRouter</a></div><ul><li><a href="/samples/BasicMediaRouter/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/BasicMediaRouter/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/BasicMediaRouter/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/BasicMediaRouter/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/BasicMediaRouter/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/BasicMediaRouter/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/BasicMediaRouter/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/BasicMediaRouter/res/layout/display.html" title="display.xml">display.xml</a></li><li><a href="/samples/BasicMediaRouter/res/layout/sample_main.html" title="sample_main.xml">sample_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/BasicMediaRouter/res/menu/main.html" title="main.xml">main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/BasicMediaRouter/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/BasicMediaRouter/res/values/colors.html" title="colors.xml">colors.xml</a></li><li><a href="/samples/BasicMediaRouter/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicMediaRouter/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/BasicMediaRouter/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/BasicMediaRouter/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicMediaRouter/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.basicmediarouter">com.example.android.basicmediarouter/</a></div><ul><li><a href="/samples/BasicMediaRouter/src/com.example.android.basicmediarouter/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li><li><a href="/samples/BasicMediaRouter/src/com.example.android.basicmediarouter/SamplePresentation.html" title="SamplePresentation.java">SamplePresentation.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common.logger">com.example.android.common.logger/</a></div><ul><li><a href="/samples/BasicMediaRouter/src/com.example.android.common.logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/BasicMediaRouter/src/com.example.android.common.logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/BasicMediaRouter/src/com.example.android.common.logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/BasicMediaRouter/src/com.example.android.common.logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/BasicMediaRouter/src/com.example.android.common.logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/BasicMediaRouter/src/com.example.android.common.logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/BasicMediaDecoder/index.html" title="BasicMediaDecoder">BasicMediaDecoder</a></div><ul><li><a href="/samples/BasicMediaDecoder/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable">drawable/</a></div><ul><li><a href="/samples/BasicMediaDecoder/res/drawable/selector_play.html" title="selector_play.xml">selector_play.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/BasicMediaDecoder/res/drawable-hdpi/ic_action_play.html" title="ic_action_play.png">ic_action_play.png</a></li><li><a href="/samples/BasicMediaDecoder/res/drawable-hdpi/ic_action_play_disabled.html" title="ic_action_play_disabled.png">ic_action_play_disabled.png</a></li><li><a href="/samples/BasicMediaDecoder/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/BasicMediaDecoder/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/BasicMediaDecoder/res/drawable-mdpi/ic_action_play.html" title="ic_action_play.png">ic_action_play.png</a></li><li><a href="/samples/BasicMediaDecoder/res/drawable-mdpi/ic_action_play_disabled.html" title="ic_action_play_disabled.png">ic_action_play_disabled.png</a></li><li><a href="/samples/BasicMediaDecoder/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/BasicMediaDecoder/res/drawable-xhdpi/ic_action_play.html" title="ic_action_play.png">ic_action_play.png</a></li><li><a href="/samples/BasicMediaDecoder/res/drawable-xhdpi/ic_action_play_disabled.html" title="ic_action_play_disabled.png">ic_action_play_disabled.png</a></li><li><a href="/samples/BasicMediaDecoder/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/BasicMediaDecoder/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/BasicMediaDecoder/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/BasicMediaDecoder/res/layout/sample_main.html" title="sample_main.xml">sample_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/BasicMediaDecoder/res/menu/action_menu.html" title="action_menu.xml">action_menu.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="raw">raw/</a></div><ul><li><a href="/samples/BasicMediaDecoder/res/raw/vid_bigbuckbunny.html" title="vid_bigbuckbunny.mp4">vid_bigbuckbunny.mp4</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/BasicMediaDecoder/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/BasicMediaDecoder/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicMediaDecoder/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/BasicMediaDecoder/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/BasicMediaDecoder/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicMediaDecoder/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.basicmediadecoder">com.example.android.basicmediadecoder/</a></div><ul><li><a href="/samples/BasicMediaDecoder/src/com.example.android.basicmediadecoder/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common.media">com.example.android.common.media/</a></div><ul><li><a href="/samples/BasicMediaDecoder/src/com.example.android.common.media/CameraHelper.html" title="CameraHelper.java">CameraHelper.java</a></li><li><a href="/samples/BasicMediaDecoder/src/com.example.android.common.media/MediaCodecWrapper.html" title="MediaCodecWrapper.java">MediaCodecWrapper.java</a></li></ul></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/security.html" title="Security">Security</a></div><ul><li class="nav-section"><div class="nav-section-header"><a href="/samples/BasicAndroidKeyStore/index.html" title="BasicAndroidKeyStore">BasicAndroidKeyStore</a></div><ul><li><a href="/samples/BasicAndroidKeyStore/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/BasicAndroidKeyStore/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/BasicAndroidKeyStore/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/BasicAndroidKeyStore/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/BasicAndroidKeyStore/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/BasicAndroidKeyStore/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/BasicAndroidKeyStore/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/BasicAndroidKeyStore/res/menu/main.html" title="main.xml">main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/BasicAndroidKeyStore/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/BasicAndroidKeyStore/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicAndroidKeyStore/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/BasicAndroidKeyStore/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/BasicAndroidKeyStore/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicAndroidKeyStore/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.basicandroidkeystore">com.example.android.basicandroidkeystore/</a></div><ul><li><a href="/samples/BasicAndroidKeyStore/src/com.example.android.basicandroidkeystore/BasicAndroidKeyStoreFragment.html" title="BasicAndroidKeyStoreFragment.java">BasicAndroidKeyStoreFragment.java</a></li><li><a href="/samples/BasicAndroidKeyStore/src/com.example.android.basicandroidkeystore/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li><li><a href="/samples/BasicAndroidKeyStore/src/com.example.android.basicandroidkeystore/SecurityConstants.html" title="SecurityConstants.java">SecurityConstants.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common">com.example.android.common/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="activities">activities/</a></div><ul><li><a href="/samples/BasicAndroidKeyStore/src/com.example.android.common/activities/SampleActivityBase.html" title="SampleActivityBase.java">SampleActivityBase.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="logger">logger/</a></div><ul><li><a href="/samples/BasicAndroidKeyStore/src/com.example.android.common/logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/BasicAndroidKeyStore/src/com.example.android.common/logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/BasicAndroidKeyStore/src/com.example.android.common/logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/BasicAndroidKeyStore/src/com.example.android.common/logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/BasicAndroidKeyStore/src/com.example.android.common/logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/BasicAndroidKeyStore/src/com.example.android.common/logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li></ul></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/testing.html" title="Testing">Testing</a></div><ul><li class="nav-section"><div class="nav-section-header"><a href="/samples/ActivityInstrumentation/index.html" title="ActivityInstrumentation">ActivityInstrumentation</a></div><ul><li><a href="/samples/ActivityInstrumentation/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/ActivityInstrumentation/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/ActivityInstrumentation/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/ActivityInstrumentation/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/ActivityInstrumentation/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/ActivityInstrumentation/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/ActivityInstrumentation/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/ActivityInstrumentation/res/layout/sample_main.html" title="sample_main.xml">sample_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/ActivityInstrumentation/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/ActivityInstrumentation/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/ActivityInstrumentation/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/ActivityInstrumentation/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/ActivityInstrumentation/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/ActivityInstrumentation/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw720dp-land">values-sw720dp-land/</a></div><ul><li><a href="/samples/ActivityInstrumentation/res/values-sw720dp-land/dimens.html" title="dimens.xml">dimens.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.activityinstrumentation">com.example.android.activityinstrumentation/</a></div><ul><li><a href="/samples/ActivityInstrumentation/src/com.example.android.activityinstrumentation/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common.logger">com.example.android.common.logger/</a></div><ul><li><a href="/samples/ActivityInstrumentation/src/com.example.android.common.logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/ActivityInstrumentation/src/com.example.android.common.logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/ActivityInstrumentation/src/com.example.android.common.logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/ActivityInstrumentation/src/com.example.android.common.logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/ActivityInstrumentation/src/com.example.android.common.logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/ActivityInstrumentation/src/com.example.android.common.logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/ui.html" title="UI">UI</a></div><ul><li class="nav-section"><div class="nav-section-header"><a href="/samples/BasicAccessibility/index.html" title="BasicAccessibility">BasicAccessibility</a></div><ul><li><a href="/samples/BasicAccessibility/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/BasicAccessibility/res/drawable-hdpi/ic_action_discard.html" title="ic_action_discard.png">ic_action_discard.png</a></li><li><a href="/samples/BasicAccessibility/res/drawable-hdpi/ic_action_info.html" title="ic_action_info.png">ic_action_info.png</a></li><li><a href="/samples/BasicAccessibility/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/BasicAccessibility/res/drawable-hdpi/partly_cloudy.html" title="partly_cloudy.png">partly_cloudy.png</a></li><li><a href="/samples/BasicAccessibility/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/BasicAccessibility/res/drawable-mdpi/ic_action_discard.html" title="ic_action_discard.png">ic_action_discard.png</a></li><li><a href="/samples/BasicAccessibility/res/drawable-mdpi/ic_action_info.html" title="ic_action_info.png">ic_action_info.png</a></li><li><a href="/samples/BasicAccessibility/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/BasicAccessibility/res/drawable-xhdpi/ic_action_discard.html" title="ic_action_discard.png">ic_action_discard.png</a></li><li><a href="/samples/BasicAccessibility/res/drawable-xhdpi/ic_action_info.html" title="ic_action_info.png">ic_action_info.png</a></li><li><a href="/samples/BasicAccessibility/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/BasicAccessibility/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/BasicAccessibility/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/BasicAccessibility/res/layout/sample_main.html" title="sample_main.xml">sample_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/BasicAccessibility/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/BasicAccessibility/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicAccessibility/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/BasicAccessibility/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/BasicAccessibility/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicAccessibility/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw720dp-land">values-sw720dp-land/</a></div><ul><li><a href="/samples/BasicAccessibility/res/values-sw720dp-land/dimens.html" title="dimens.xml">dimens.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.basicaccessibility">com.example.android.basicaccessibility/</a></div><ul><li><a href="/samples/BasicAccessibility/src/com.example.android.basicaccessibility/DialView.html" title="DialView.java">DialView.java</a></li><li><a href="/samples/BasicAccessibility/src/com.example.android.basicaccessibility/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common.logger">com.example.android.common.logger/</a></div><ul><li><a href="/samples/BasicAccessibility/src/com.example.android.common.logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/BasicAccessibility/src/com.example.android.common.logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/BasicAccessibility/src/com.example.android.common.logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/BasicAccessibility/src/com.example.android.common.logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/BasicAccessibility/src/com.example.android.common.logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/BasicAccessibility/src/com.example.android.common.logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/HorizontalPaging/index.html" title="HorizontalPaging">HorizontalPaging</a></div><ul><li><a href="/samples/HorizontalPaging/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/HorizontalPaging/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/HorizontalPaging/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/HorizontalPaging/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/HorizontalPaging/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/HorizontalPaging/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/HorizontalPaging/res/layout/fragment_main_dummy.html" title="fragment_main_dummy.xml">fragment_main_dummy.xml</a></li><li><a href="/samples/HorizontalPaging/res/layout/sample_main.html" title="sample_main.xml">sample_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/HorizontalPaging/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/HorizontalPaging/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/HorizontalPaging/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/HorizontalPaging/res/values/styles.html" title="styles.xml">styles.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw720dp-land">values-sw720dp-land/</a></div><ul><li><a href="/samples/HorizontalPaging/res/values/values-sw720dp-land/dimens.html" title="dimens.xml">dimens.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/HorizontalPaging/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/HorizontalPaging/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.horizontalpaging">com.example.android.horizontalpaging/</a></div><ul><li><a href="/samples/HorizontalPaging/src/com.example.android.horizontalpaging/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/ShareActionProvider/index.html" title="ShareActionProvider">ShareActionProvider</a></div><ul><li><a href="/samples/ShareActionProvider/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/ShareActionProvider/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/ShareActionProvider/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/ShareActionProvider/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/ShareActionProvider/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/ShareActionProvider/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/ShareActionProvider/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/ShareActionProvider/res/layout/item_image.html" title="item_image.xml">item_image.xml</a></li><li><a href="/samples/ShareActionProvider/res/layout/item_text.html" title="item_text.xml">item_text.xml</a></li><li><a href="/samples/ShareActionProvider/res/layout/sample_main.html" title="sample_main.xml">sample_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/ShareActionProvider/res/menu/main_menu.html" title="main_menu.xml">main_menu.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/ShareActionProvider/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/ShareActionProvider/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/ShareActionProvider/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/ShareActionProvider/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/ShareActionProvider/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/ShareActionProvider/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.actionbarcompat.shareactionprovider">com.example.android.actionbarcompat.shareactionprovider/</a></div><ul><li><a href="/samples/ShareActionProvider/src/com.example.android.actionbarcompat.shareactionprovider/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="content">content/</a></div><ul><li><a href="/samples/ShareActionProvider/src/com.example.android.actionbarcompat.shareactionprovider/content/AssetProvider.html" title="AssetProvider.java">AssetProvider.java</a></li><li><a href="/samples/ShareActionProvider/src/com.example.android.actionbarcompat.shareactionprovider/content/ContentItem.html" title="ContentItem.java">ContentItem.java</a></li></ul></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/Styled/index.html" title="Styled">Styled</a></div><ul><li><a href="/samples/Styled/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable">drawable/</a></div><ul><li><a href="/samples/Styled/res/drawable/pressed_background.html" title="pressed_background.xml">pressed_background.xml</a></li><li><a href="/samples/Styled/res/drawable/progress_horizontal.html" title="progress_horizontal.xml">progress_horizontal.xml</a></li><li><a href="/samples/Styled/res/drawable/selectable_background.html" title="selectable_background.xml">selectable_background.xml</a></li><li><a href="/samples/Styled/res/drawable/spinner_background_ab.html" title="spinner_background_ab.xml">spinner_background_ab.xml</a></li><li><a href="/samples/Styled/res/drawable/tab_indicator_ab.html" title="tab_indicator_ab.xml">tab_indicator_ab.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/Styled/res/drawable-hdpi/ab_bottom_solid_styled.9.html" title="ab_bottom_solid_styled.9.png">ab_bottom_solid_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/ab_solid_styled.9.html" title="ab_solid_styled.9.png">ab_solid_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/ab_stacked_solid_styled.9.html" title="ab_stacked_solid_styled.9.png">ab_stacked_solid_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/ic_action_location.html" title="ic_action_location.png">ic_action_location.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/ic_action_refresh.html" title="ic_action_refresh.png">ic_action_refresh.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/ic_action_settings.html" title="ic_action_settings.png">ic_action_settings.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/list_focused_styled.9.html" title="list_focused_styled.9.png">list_focused_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/menu_dropdown_panel_styled.9.html" title="menu_dropdown_panel_styled.9.png">menu_dropdown_panel_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/progress_bg_styled.9.html" title="progress_bg_styled.9.png">progress_bg_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/progress_primary_styled.9.html" title="progress_primary_styled.9.png">progress_primary_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/progress_secondary_styled.9.html" title="progress_secondary_styled.9.png">progress_secondary_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/spinner_ab_default_styled.9.html" title="spinner_ab_default_styled.9.png">spinner_ab_default_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/spinner_ab_disabled_styled.9.html" title="spinner_ab_disabled_styled.9.png">spinner_ab_disabled_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/spinner_ab_focused_styled.9.html" title="spinner_ab_focused_styled.9.png">spinner_ab_focused_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/spinner_ab_pressed_styled.9.html" title="spinner_ab_pressed_styled.9.png">spinner_ab_pressed_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/tab_selected_focused_styled.9.html" title="tab_selected_focused_styled.9.png">tab_selected_focused_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/tab_selected_pressed_styled.9.html" title="tab_selected_pressed_styled.9.png">tab_selected_pressed_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/tab_selected_styled.9.html" title="tab_selected_styled.9.png">tab_selected_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/tab_unselected_focused_styled.9.html" title="tab_unselected_focused_styled.9.png">tab_unselected_focused_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/tab_unselected_pressed_styled.9.html" title="tab_unselected_pressed_styled.9.png">tab_unselected_pressed_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/Styled/res/drawable-mdpi/ab_bottom_solid_styled.9.html" title="ab_bottom_solid_styled.9.png">ab_bottom_solid_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/ab_solid_styled.9.html" title="ab_solid_styled.9.png">ab_solid_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/ab_stacked_solid_styled.9.html" title="ab_stacked_solid_styled.9.png">ab_stacked_solid_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/ic_action_location.html" title="ic_action_location.png">ic_action_location.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/ic_action_refresh.html" title="ic_action_refresh.png">ic_action_refresh.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/ic_action_settings.html" title="ic_action_settings.png">ic_action_settings.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/list_focused_styled.9.html" title="list_focused_styled.9.png">list_focused_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/menu_dropdown_panel_styled.9.html" title="menu_dropdown_panel_styled.9.png">menu_dropdown_panel_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/progress_bg_styled.9.html" title="progress_bg_styled.9.png">progress_bg_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/progress_primary_styled.9.html" title="progress_primary_styled.9.png">progress_primary_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/progress_secondary_styled.9.html" title="progress_secondary_styled.9.png">progress_secondary_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/spinner_ab_default_styled.9.html" title="spinner_ab_default_styled.9.png">spinner_ab_default_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/spinner_ab_disabled_styled.9.html" title="spinner_ab_disabled_styled.9.png">spinner_ab_disabled_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/spinner_ab_focused_styled.9.html" title="spinner_ab_focused_styled.9.png">spinner_ab_focused_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/spinner_ab_pressed_styled.9.html" title="spinner_ab_pressed_styled.9.png">spinner_ab_pressed_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/tab_selected_focused_styled.9.html" title="tab_selected_focused_styled.9.png">tab_selected_focused_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/tab_selected_pressed_styled.9.html" title="tab_selected_pressed_styled.9.png">tab_selected_pressed_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/tab_selected_styled.9.html" title="tab_selected_styled.9.png">tab_selected_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/tab_unselected_focused_styled.9.html" title="tab_unselected_focused_styled.9.png">tab_unselected_focused_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/tab_unselected_pressed_styled.9.html" title="tab_unselected_pressed_styled.9.png">tab_unselected_pressed_styled.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/Styled/res/drawable-xhdpi/ab_bottom_solid_styled.9.html" title="ab_bottom_solid_styled.9.png">ab_bottom_solid_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/ab_solid_styled.9.html" title="ab_solid_styled.9.png">ab_solid_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/ab_stacked_solid_styled.9.html" title="ab_stacked_solid_styled.9.png">ab_stacked_solid_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/ic_action_location.html" title="ic_action_location.png">ic_action_location.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/ic_action_refresh.html" title="ic_action_refresh.png">ic_action_refresh.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/ic_action_settings.html" title="ic_action_settings.png">ic_action_settings.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/list_focused_styled.9.html" title="list_focused_styled.9.png">list_focused_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/menu_dropdown_panel_styled.9.html" title="menu_dropdown_panel_styled.9.png">menu_dropdown_panel_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/progress_bg_styled.9.html" title="progress_bg_styled.9.png">progress_bg_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/progress_primary_styled.9.html" title="progress_primary_styled.9.png">progress_primary_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/progress_secondary_styled.9.html" title="progress_secondary_styled.9.png">progress_secondary_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/spinner_ab_default_styled.9.html" title="spinner_ab_default_styled.9.png">spinner_ab_default_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/spinner_ab_disabled_styled.9.html" title="spinner_ab_disabled_styled.9.png">spinner_ab_disabled_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/spinner_ab_focused_styled.9.html" title="spinner_ab_focused_styled.9.png">spinner_ab_focused_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/spinner_ab_pressed_styled.9.html" title="spinner_ab_pressed_styled.9.png">spinner_ab_pressed_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/tab_selected_focused_styled.9.html" title="tab_selected_focused_styled.9.png">tab_selected_focused_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/tab_selected_pressed_styled.9.html" title="tab_selected_pressed_styled.9.png">tab_selected_pressed_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/tab_selected_styled.9.html" title="tab_selected_styled.9.png">tab_selected_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/tab_unselected_focused_styled.9.html" title="tab_unselected_focused_styled.9.png">tab_unselected_focused_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/tab_unselected_pressed_styled.9.html" title="tab_unselected_pressed_styled.9.png">tab_unselected_pressed_styled.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/Styled/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/Styled/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/Styled/res/layout/sample_main.html" title="sample_main.xml">sample_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/Styled/res/menu/main.html" title="main.xml">main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/Styled/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/Styled/res/values/colors.html" title="colors.xml">colors.xml</a></li><li><a href="/samples/Styled/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/Styled/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/Styled/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/Styled/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/Styled/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-v14">values-v14/</a></div><ul><li><a href="/samples/Styled/res/values-v14/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.actionbarcompat.styled">com.example.android.actionbarcompat.styled/</a></div><ul><li><a href="/samples/Styled/src/com.example.android.actionbarcompat.styled/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/Basic/index.html" title="Basic">Basic</a></div><ul><li><a href="/samples/Basic/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/Basic/res/drawable-hdpi/ic_action_location.html" title="ic_action_location.png">ic_action_location.png</a></li><li><a href="/samples/Basic/res/drawable-hdpi/ic_action_refresh.html" title="ic_action_refresh.png">ic_action_refresh.png</a></li><li><a href="/samples/Basic/res/drawable-hdpi/ic_action_settings.html" title="ic_action_settings.png">ic_action_settings.png</a></li><li><a href="/samples/Basic/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/Basic/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/Basic/res/drawable-mdpi/ic_action_location.html" title="ic_action_location.png">ic_action_location.png</a></li><li><a href="/samples/Basic/res/drawable-mdpi/ic_action_refresh.html" title="ic_action_refresh.png">ic_action_refresh.png</a></li><li><a href="/samples/Basic/res/drawable-mdpi/ic_action_settings.html" title="ic_action_settings.png">ic_action_settings.png</a></li><li><a href="/samples/Basic/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/Basic/res/drawable-xhdpi/ic_action_location.html" title="ic_action_location.png">ic_action_location.png</a></li><li><a href="/samples/Basic/res/drawable-xhdpi/ic_action_refresh.html" title="ic_action_refresh.png">ic_action_refresh.png</a></li><li><a href="/samples/Basic/res/drawable-xhdpi/ic_action_settings.html" title="ic_action_settings.png">ic_action_settings.png</a></li><li><a href="/samples/Basic/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/Basic/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/Basic/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/Basic/res/layout/sample_main.html" title="sample_main.xml">sample_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/Basic/res/menu/main.html" title="main.xml">main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/Basic/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/Basic/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/Basic/res/values/ids.html" title="ids.xml">ids.xml</a></li><li><a href="/samples/Basic/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/Basic/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/Basic/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/Basic/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.actionbarcompat.basic">com.example.android.actionbarcompat.basic/</a></div><ul><li><a href="/samples/Basic/src/com.example.android.actionbarcompat.basic/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/ImmersiveMode/index.html" title="ImmersiveMode">ImmersiveMode</a></div><ul><li><a href="/samples/ImmersiveMode/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/ImmersiveMode/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/ImmersiveMode/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/ImmersiveMode/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/ImmersiveMode/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/ImmersiveMode/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/ImmersiveMode/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/ImmersiveMode/res/menu/main.html" title="main.xml">main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/ImmersiveMode/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/ImmersiveMode/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/ImmersiveMode/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/ImmersiveMode/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/ImmersiveMode/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/ImmersiveMode/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common">com.example.android.common/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="activities">activities/</a></div><ul><li><a href="/samples/ImmersiveMode/src/com.example.android.common/activities/SampleActivityBase.html" title="SampleActivityBase.java">SampleActivityBase.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="logger">logger/</a></div><ul><li><a href="/samples/ImmersiveMode/src/com.example.android.common/logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/ImmersiveMode/src/com.example.android.common/logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/ImmersiveMode/src/com.example.android.common/logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/ImmersiveMode/src/com.example.android.common/logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/ImmersiveMode/src/com.example.android.common/logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/ImmersiveMode/src/com.example.android.common/logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.immersivemode">com.example.android.immersivemode/</a></div><ul><li><a href="/samples/ImmersiveMode/src/com.example.android.immersivemode/ImmersiveModeFragment.html" title="ImmersiveModeFragment.java">ImmersiveModeFragment.java</a></li><li><a href="/samples/ImmersiveMode/src/com.example.android.immersivemode/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/TextSwitcher/index.html" title="TextSwitcher">TextSwitcher</a></div><ul><li><a href="/samples/TextSwitcher/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/TextSwitcher/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/TextSwitcher/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/TextSwitcher/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/TextSwitcher/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/TextSwitcher/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/TextSwitcher/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/TextSwitcher/res/layout/sample_main.html" title="sample_main.xml">sample_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/TextSwitcher/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/TextSwitcher/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/TextSwitcher/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/TextSwitcher/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/TextSwitcher/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/TextSwitcher/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw720dp-land">values-sw720dp-land/</a></div><ul><li><a href="/samples/TextSwitcher/res/values-sw720dp-land/dimens.html" title="dimens.xml">dimens.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-v11">values-v11/</a></div><ul><li><a href="/samples/TextSwitcher/res/values-v11/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-v14">values-v14/</a></div><ul><li><a href="/samples/TextSwitcher/res/values-v14/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common.logger">com.example.android.common.logger/</a></div><ul><li><a href="/samples/TextSwitcher/src/com.example.android.common.logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/TextSwitcher/src/com.example.android.common.logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/TextSwitcher/src/com.example.android.common.logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/TextSwitcher/src/com.example.android.common.logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/TextSwitcher/src/com.example.android.common.logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/TextSwitcher/src/com.example.android.common.logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.textswitcher">com.example.android.textswitcher/</a></div><ul><li><a href="/samples/TextSwitcher/src/com.example.android.textswitcher/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/BorderlessButtons/index.html" title="BorderlessButtons">BorderlessButtons</a></div><ul><li><a href="/samples/BorderlessButtons/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/BorderlessButtons/res/drawable-hdpi/ic_action_delete.html" title="ic_action_delete.png">ic_action_delete.png</a></li><li><a href="/samples/BorderlessButtons/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/BorderlessButtons/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/BorderlessButtons/res/drawable-mdpi/ic_action_delete.html" title="ic_action_delete.png">ic_action_delete.png</a></li><li><a href="/samples/BorderlessButtons/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/BorderlessButtons/res/drawable-xhdpi/ic_action_delete.html" title="ic_action_delete.png">ic_action_delete.png</a></li><li><a href="/samples/BorderlessButtons/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/BorderlessButtons/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/BorderlessButtons/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/BorderlessButtons/res/layout/list_item.html" title="list_item.xml">list_item.xml</a></li><li><a href="/samples/BorderlessButtons/res/layout/sample_main.html" title="sample_main.xml">sample_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/BorderlessButtons/res/menu/main.html" title="main.xml">main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/BorderlessButtons/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/BorderlessButtons/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BorderlessButtons/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/BorderlessButtons/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/BorderlessButtons/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BorderlessButtons/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.borderlessbuttons">com.example.android.borderlessbuttons/</a></div><ul><li><a href="/samples/BorderlessButtons/src/com.example.android.borderlessbuttons/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common.logger">com.example.android.common.logger/</a></div><ul><li><a href="/samples/BorderlessButtons/src/com.example.android.common.logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/BorderlessButtons/src/com.example.android.common.logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/BorderlessButtons/src/com.example.android.common.logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/BorderlessButtons/src/com.example.android.common.logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/BorderlessButtons/src/com.example.android.common.logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/BorderlessButtons/src/com.example.android.common.logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/BasicNotifications/index.html" title="BasicNotifications">BasicNotifications</a></div><ul><li><a href="/samples/BasicNotifications/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/BasicNotifications/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/BasicNotifications/res/drawable-hdpi/ic_stat_notification.html" title="ic_stat_notification.png">ic_stat_notification.png</a></li><li><a href="/samples/BasicNotifications/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi-v11">drawable-hdpi-v11/</a></div><ul><li><a href="/samples/BasicNotifications/res/drawable-hdpi-v11/ic_stat_notification.html" title="ic_stat_notification.png">ic_stat_notification.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi-v9">drawable-hdpi-v9/</a></div><ul><li><a href="/samples/BasicNotifications/res/drawable-hdpi-v9/ic_stat_notification.html" title="ic_stat_notification.png">ic_stat_notification.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-ldpi-v11">drawable-ldpi-v11/</a></div><ul><li><a href="/samples/BasicNotifications/res/drawable-ldpi-v11/ic_stat_notification.html" title="ic_stat_notification.png">ic_stat_notification.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-ldpi-v9">drawable-ldpi-v9/</a></div><ul><li><a href="/samples/BasicNotifications/res/drawable-ldpi-v9/ic_stat_notification.html" title="ic_stat_notification.png">ic_stat_notification.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/BasicNotifications/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/BasicNotifications/res/drawable-mdpi/ic_stat_notification.html" title="ic_stat_notification.png">ic_stat_notification.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi-v11">drawable-mdpi-v11/</a></div><ul><li><a href="/samples/BasicNotifications/res/drawable-mdpi-v11/ic_stat_notification.html" title="ic_stat_notification.png">ic_stat_notification.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi-v9">drawable-mdpi-v9/</a></div><ul><li><a href="/samples/BasicNotifications/res/drawable-mdpi-v9/ic_stat_notification.html" title="ic_stat_notification.png">ic_stat_notification.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/BasicNotifications/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/BasicNotifications/res/drawable-xhdpi/ic_stat_notification.html" title="ic_stat_notification.png">ic_stat_notification.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi-v11">drawable-xhdpi-v11/</a></div><ul><li><a href="/samples/BasicNotifications/res/drawable-xhdpi-v11/ic_stat_notification.html" title="ic_stat_notification.png">ic_stat_notification.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi-v9">drawable-xhdpi-v9/</a></div><ul><li><a href="/samples/BasicNotifications/res/drawable-xhdpi-v9/ic_stat_notification.html" title="ic_stat_notification.png">ic_stat_notification.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/BasicNotifications/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/BasicNotifications/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/BasicNotifications/res/layout/sample_layout.html" title="sample_layout.xml">sample_layout.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/BasicNotifications/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/BasicNotifications/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicNotifications/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/BasicNotifications/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/BasicNotifications/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicNotifications/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.basicnotifications">com.example.android.basicnotifications/</a></div><ul><li><a href="/samples/BasicNotifications/src/com.example.android.basicnotifications/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/AdvancedImmersiveMode/index.html" title="AdvancedImmersiveMode">AdvancedImmersiveMode</a></div><ul><li><a href="/samples/AdvancedImmersiveMode/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/AdvancedImmersiveMode/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/AdvancedImmersiveMode/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/AdvancedImmersiveMode/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/AdvancedImmersiveMode/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/AdvancedImmersiveMode/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/AdvancedImmersiveMode/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/AdvancedImmersiveMode/res/menu/main.html" title="main.xml">main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/AdvancedImmersiveMode/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/AdvancedImmersiveMode/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/AdvancedImmersiveMode/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/AdvancedImmersiveMode/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/AdvancedImmersiveMode/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/AdvancedImmersiveMode/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.advancedimmersivemode">com.example.android.advancedimmersivemode/</a></div><ul><li><a href="/samples/AdvancedImmersiveMode/src/com.example.android.advancedimmersivemode/AdvancedImmersiveModeFragment.html" title="AdvancedImmersiveModeFragment.java">AdvancedImmersiveModeFragment.java</a></li><li><a href="/samples/AdvancedImmersiveMode/src/com.example.android.advancedimmersivemode/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common">com.example.android.common/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="activities">activities/</a></div><ul><li><a href="/samples/AdvancedImmersiveMode/src/com.example.android.common/activities/SampleActivityBase.html" title="SampleActivityBase.java">SampleActivityBase.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="logger">logger/</a></div><ul><li><a href="/samples/AdvancedImmersiveMode/src/com.example.android.common/logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/AdvancedImmersiveMode/src/com.example.android.common/logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/AdvancedImmersiveMode/src/com.example.android.common/logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/AdvancedImmersiveMode/src/com.example.android.common/logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/AdvancedImmersiveMode/src/com.example.android.common/logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/AdvancedImmersiveMode/src/com.example.android.common/logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/BasicImmersiveMode/index.html" title="BasicImmersiveMode">BasicImmersiveMode</a></div><ul><li><a href="/samples/BasicImmersiveMode/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/BasicImmersiveMode/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/BasicImmersiveMode/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/BasicImmersiveMode/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/BasicImmersiveMode/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/BasicImmersiveMode/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/BasicImmersiveMode/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/BasicImmersiveMode/res/menu/main.html" title="main.xml">main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/BasicImmersiveMode/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/BasicImmersiveMode/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicImmersiveMode/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/BasicImmersiveMode/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/BasicImmersiveMode/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicImmersiveMode/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.basicimmersivemode">com.example.android.basicimmersivemode/</a></div><ul><li><a href="/samples/BasicImmersiveMode/src/com.example.android.basicimmersivemode/BasicImmersiveModeFragment.html" title="BasicImmersiveModeFragment.java">BasicImmersiveModeFragment.java</a></li><li><a href="/samples/BasicImmersiveMode/src/com.example.android.basicimmersivemode/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common">com.example.android.common/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="activities">activities/</a></div><ul><li><a href="/samples/BasicImmersiveMode/src/com.example.android.common/activities/SampleActivityBase.html" title="SampleActivityBase.java">SampleActivityBase.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="logger">logger/</a></div><ul><li><a href="/samples/BasicImmersiveMode/src/com.example.android.common/logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/BasicImmersiveMode/src/com.example.android.common/logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/BasicImmersiveMode/src/com.example.android.common/logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/BasicImmersiveMode/src/com.example.android.common/logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/BasicImmersiveMode/src/com.example.android.common/logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/BasicImmersiveMode/src/com.example.android.common/logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/CustomChoiceList/index.html" title="CustomChoiceList">CustomChoiceList</a></div><ul><li><a href="/samples/CustomChoiceList/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="color">color/</a></div><ul><li><a href="/samples/CustomChoiceList/res/color/hideable_text_color.html" title="hideable_text_color.xml">hideable_text_color.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable">drawable/</a></div><ul><li><a href="/samples/CustomChoiceList/res/drawable/ic_hideable_item.html" title="ic_hideable_item.xml">ic_hideable_item.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/CustomChoiceList/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/CustomChoiceList/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/CustomChoiceList/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/CustomChoiceList/res/drawable-xhdpi/ic_hideable_item_checked.html" title="ic_hideable_item_checked.png">ic_hideable_item_checked.png</a></li><li><a href="/samples/CustomChoiceList/res/drawable-xhdpi/ic_hideable_item_unchecked.html" title="ic_hideable_item_unchecked.png">ic_hideable_item_unchecked.png</a></li><li><a href="/samples/CustomChoiceList/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/CustomChoiceList/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/CustomChoiceList/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/CustomChoiceList/res/layout/list_item.html" title="list_item.xml">list_item.xml</a></li><li><a href="/samples/CustomChoiceList/res/layout/sample_main.html" title="sample_main.xml">sample_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/CustomChoiceList/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/CustomChoiceList/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/CustomChoiceList/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/CustomChoiceList/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/CustomChoiceList/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common.logger">com.example.android.common.logger/</a></div><ul><li><a href="/samples/CustomChoiceList/src/com.example.android.common.logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/CustomChoiceList/src/com.example.android.common.logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/CustomChoiceList/src/com.example.android.common.logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/CustomChoiceList/src/com.example.android.common.logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/CustomChoiceList/src/com.example.android.common.logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/CustomChoiceList/src/com.example.android.common.logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.customchoicelist">com.example.android.customchoicelist/</a></div><ul><li><a href="/samples/CustomChoiceList/src/com.example.android.customchoicelist/CheckableLinearLayout.html" title="CheckableLinearLayout.java">CheckableLinearLayout.java</a></li><li><a href="/samples/CustomChoiceList/src/com.example.android.customchoicelist/Cheeses.html" title="Cheeses.java">Cheeses.java</a></li><li><a href="/samples/CustomChoiceList/src/com.example.android.customchoicelist/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/DoneBar/index.html" title="DoneBar">DoneBar</a></div><ul><li><a href="/samples/DoneBar/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/DoneBar/res/drawable-hdpi/ic_action_cancel.html" title="ic_action_cancel.png">ic_action_cancel.png</a></li><li><a href="/samples/DoneBar/res/drawable-hdpi/ic_action_done.html" title="ic_action_done.png">ic_action_done.png</a></li><li><a href="/samples/DoneBar/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/DoneBar/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/DoneBar/res/drawable-mdpi/ic_action_cancel.html" title="ic_action_cancel.png">ic_action_cancel.png</a></li><li><a href="/samples/DoneBar/res/drawable-mdpi/ic_action_done.html" title="ic_action_done.png">ic_action_done.png</a></li><li><a href="/samples/DoneBar/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/DoneBar/res/drawable-xhdpi/ic_action_cancel.html" title="ic_action_cancel.png">ic_action_cancel.png</a></li><li><a href="/samples/DoneBar/res/drawable-xhdpi/ic_action_done.html" title="ic_action_done.png">ic_action_done.png</a></li><li><a href="/samples/DoneBar/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/DoneBar/res/drawable-xhdpi/sample_dashboard_item_background.9.html" title="sample_dashboard_item_background.9.png">sample_dashboard_item_background.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/DoneBar/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/DoneBar/res/layout/actionbar_custom_view_done.html" title="actionbar_custom_view_done.xml">actionbar_custom_view_done.xml</a></li><li><a href="/samples/DoneBar/res/layout/actionbar_custom_view_done_cancel.html" title="actionbar_custom_view_done_cancel.xml">actionbar_custom_view_done_cancel.xml</a></li><li><a href="/samples/DoneBar/res/layout/activity_done_bar.html" title="activity_done_bar.xml">activity_done_bar.xml</a></li><li><a href="/samples/DoneBar/res/layout/activity_done_button.html" title="activity_done_button.xml">activity_done_button.xml</a></li><li><a href="/samples/DoneBar/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/DoneBar/res/layout/activity_sample_dashboard.html" title="activity_sample_dashboard.xml">activity_sample_dashboard.xml</a></li><li><a href="/samples/DoneBar/res/layout/include_cancel_button.html" title="include_cancel_button.xml">include_cancel_button.xml</a></li><li><a href="/samples/DoneBar/res/layout/include_done_button.html" title="include_done_button.xml">include_done_button.xml</a></li><li><a href="/samples/DoneBar/res/layout/sample_dashboard_item.html" title="sample_dashboard_item.xml">sample_dashboard_item.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/DoneBar/res/menu/cancel.html" title="cancel.xml">cancel.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/DoneBar/res/values/activitycards-strings.html" title="activitycards-strings.xml">activitycards-strings.xml</a></li><li><a href="/samples/DoneBar/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/DoneBar/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/DoneBar/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/DoneBar/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/DoneBar/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/DoneBar/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.donebar">com.example.android.donebar/</a></div><ul><li><a href="/samples/DoneBar/src/com.example.android.donebar/DoneBarActivity.html" title="DoneBarActivity.java">DoneBarActivity.java</a></li><li><a href="/samples/DoneBar/src/com.example.android.donebar/DoneButtonActivity.html" title="DoneButtonActivity.java">DoneButtonActivity.java</a></li><li><a href="/samples/DoneBar/src/com.example.android.donebar/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/ListPopupMenu/index.html" title="ListPopupMenu">ListPopupMenu</a></div><ul><li><a href="/samples/ListPopupMenu/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/ListPopupMenu/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/ListPopupMenu/res/drawable-hdpi/ic_overflow.html" title="ic_overflow.png">ic_overflow.png</a></li><li><a href="/samples/ListPopupMenu/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/ListPopupMenu/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/ListPopupMenu/res/drawable-mdpi/ic_overflow.html" title="ic_overflow.png">ic_overflow.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/ListPopupMenu/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/ListPopupMenu/res/drawable-xhdpi/ic_overflow.html" title="ic_overflow.png">ic_overflow.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/ListPopupMenu/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/ListPopupMenu/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/ListPopupMenu/res/layout/list_item.html" title="list_item.xml">list_item.xml</a></li><li><a href="/samples/ListPopupMenu/res/layout/sample_main.html" title="sample_main.xml">sample_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/ListPopupMenu/res/menu/popup.html" title="popup.xml">popup.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/ListPopupMenu/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/ListPopupMenu/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/ListPopupMenu/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/ListPopupMenu/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/ListPopupMenu/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/ListPopupMenu/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.actionbarcompat.listpopupmenu">com.example.android.actionbarcompat.listpopupmenu/</a></div><ul><li><a href="/samples/ListPopupMenu/src/com.example.android.actionbarcompat.listpopupmenu/Cheeses.html" title="Cheeses.java">Cheeses.java</a></li><li><a href="/samples/ListPopupMenu/src/com.example.android.actionbarcompat.listpopupmenu/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li><li><a href="/samples/ListPopupMenu/src/com.example.android.actionbarcompat.listpopupmenu/PopupListFragment.html" title="PopupListFragment.java">PopupListFragment.java</a></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/CustomNotifications/index.html" title="CustomNotifications">CustomNotifications</a></div><ul><li><a href="/samples/CustomNotifications/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/CustomNotifications/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/CustomNotifications/res/drawable-hdpi/ic_stat_custom.html" title="ic_stat_custom.png">ic_stat_custom.png</a></li><li><a href="/samples/CustomNotifications/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi-v11">drawable-hdpi-v11/</a></div><ul><li><a href="/samples/CustomNotifications/res/drawable-hdpi-v11/ic_stat_custom.html" title="ic_stat_custom.png">ic_stat_custom.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi-v9">drawable-hdpi-v9/</a></div><ul><li><a href="/samples/CustomNotifications/res/drawable-hdpi-v9/ic_stat_custom.html" title="ic_stat_custom.png">ic_stat_custom.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-ldpi-v11">drawable-ldpi-v11/</a></div><ul><li><a href="/samples/CustomNotifications/res/drawable-ldpi-v11/ic_stat_custom.html" title="ic_stat_custom.png">ic_stat_custom.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-ldpi-v9">drawable-ldpi-v9/</a></div><ul><li><a href="/samples/CustomNotifications/res/drawable-ldpi-v9/ic_stat_custom.html" title="ic_stat_custom.png">ic_stat_custom.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/CustomNotifications/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/CustomNotifications/res/drawable-mdpi/ic_stat_custom.html" title="ic_stat_custom.png">ic_stat_custom.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi-v11">drawable-mdpi-v11/</a></div><ul><li><a href="/samples/CustomNotifications/res/drawable-mdpi-v11/ic_stat_custom.html" title="ic_stat_custom.png">ic_stat_custom.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi-v9">drawable-mdpi-v9/</a></div><ul><li><a href="/samples/CustomNotifications/res/drawable-mdpi-v9/ic_stat_custom.html" title="ic_stat_custom.png">ic_stat_custom.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/CustomNotifications/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/CustomNotifications/res/drawable-xhdpi/ic_stat_custom.html" title="ic_stat_custom.png">ic_stat_custom.png</a></li><li><a href="/samples/CustomNotifications/res/drawable-xhdpi/robot.html" title="robot.png">robot.png</a></li><li><a href="/samples/CustomNotifications/res/drawable-xhdpi/robot_expanded.html" title="robot_expanded.png">robot_expanded.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi-v11">drawable-xhdpi-v11/</a></div><ul><li><a href="/samples/CustomNotifications/res/drawable-xhdpi-v11/ic_stat_custom.html" title="ic_stat_custom.png">ic_stat_custom.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi-v9">drawable-xhdpi-v9/</a></div><ul><li><a href="/samples/CustomNotifications/res/drawable-xhdpi-v9/ic_stat_custom.html" title="ic_stat_custom.png">ic_stat_custom.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/CustomNotifications/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/CustomNotifications/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/CustomNotifications/res/layout/notification.html" title="notification.xml">notification.xml</a></li><li><a href="/samples/CustomNotifications/res/layout/notification_expanded.html" title="notification_expanded.xml">notification_expanded.xml</a></li><li><a href="/samples/CustomNotifications/res/layout/sample_main.html" title="sample_main.xml">sample_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/CustomNotifications/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/CustomNotifications/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/CustomNotifications/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/CustomNotifications/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/CustomNotifications/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/CustomNotifications/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw720dp-land">values-sw720dp-land/</a></div><ul><li><a href="/samples/CustomNotifications/res/values-sw720dp-land/dimens.html" title="dimens.xml">dimens.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-v9">values-v9/</a></div><ul><li><a href="/samples/CustomNotifications/res/values-v9/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.customnotifications">com.example.android.customnotifications/</a></div><ul><li><a href="/samples/CustomNotifications/src/com.example.android.customnotifications/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/views.html" title="Views">Views</a></div><ul><li class="nav-section"><div class="nav-section-header"><a href="/samples/TextLinkify/index.html" title="TextLinkify">TextLinkify</a></div><ul><li><a href="/samples/TextLinkify/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/TextLinkify/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/TextLinkify/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/TextLinkify/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/TextLinkify/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/TextLinkify/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/TextLinkify/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/TextLinkify/res/layout/sample_main.html" title="sample_main.xml">sample_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/TextLinkify/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/TextLinkify/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/TextLinkify/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/TextLinkify/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/TextLinkify/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/TextLinkify/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw720dp-land">values-sw720dp-land/</a></div><ul><li><a href="/samples/TextLinkify/res/values-sw720dp-land/dimens.html" title="dimens.xml">dimens.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common.logger">com.example.android.common.logger/</a></div><ul><li><a href="/samples/TextLinkify/src/com.example.android.common.logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/TextLinkify/src/com.example.android.common.logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/TextLinkify/src/com.example.android.common.logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/TextLinkify/src/com.example.android.common.logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/TextLinkify/src/com.example.android.common.logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/TextLinkify/src/com.example.android.common.logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.textlinkify">com.example.android.textlinkify/</a></div><ul><li><a href="/samples/TextLinkify/src/com.example.android.textlinkify/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li></ul></li></ul></li></ul></li></ul>
+  <li class="nav-section"><div class="nav-section-header"><a href="/samples/background.html" title="Background">Background</a></div><ul><li class="nav-section"><div class="nav-section-header"><a href="/samples/repeatingAlarm/index.html" title="repeatingAlarm">repeatingAlarm</a></div><ul><li><a href="/samples/repeatingAlarm/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/repeatingAlarm/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/repeatingAlarm/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/repeatingAlarm/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/repeatingAlarm/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/repeatingAlarm/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/repeatingAlarm/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/repeatingAlarm/res/menu/main.html" title="main.xml">main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/repeatingAlarm/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/repeatingAlarm/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/repeatingAlarm/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/repeatingAlarm/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/repeatingAlarm/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/repeatingAlarm/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common">com.example.android.common/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="activities">activities/</a></div><ul><li><a href="/samples/repeatingAlarm/src/com.example.android.common/activities/SampleActivityBase.html" title="SampleActivityBase.java">SampleActivityBase.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="logger">logger/</a></div><ul><li><a href="/samples/repeatingAlarm/src/com.example.android.common/logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/repeatingAlarm/src/com.example.android.common/logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/repeatingAlarm/src/com.example.android.common/logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/repeatingAlarm/src/com.example.android.common/logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/repeatingAlarm/src/com.example.android.common/logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/repeatingAlarm/src/com.example.android.common/logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.repeatingalarm">com.example.android.repeatingalarm/</a></div><ul><li><a href="/samples/repeatingAlarm/src/com.example.android.repeatingalarm/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li><li><a href="/samples/repeatingAlarm/src/com.example.android.repeatingalarm/RepeatingAlarmFragment.html" title="RepeatingAlarmFragment.java">RepeatingAlarmFragment.java</a></li></ul></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/connectivity.html" title="Connectivity">Connectivity</a></div><ul><li class="nav-section"><div class="nav-section-header"><a href="/samples/BluetoothLeGatt/index.html" title="BluetoothLeGatt">BluetoothLeGatt</a></div><ul><li><a href="/samples/BluetoothLeGatt/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/BluetoothLeGatt/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/BluetoothLeGatt/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/BluetoothLeGatt/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/BluetoothLeGatt/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/BluetoothLeGatt/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/BluetoothLeGatt/res/layout/actionbar_indeterminate_progress.html" title="actionbar_indeterminate_progress.xml">actionbar_indeterminate_progress.xml</a></li><li><a href="/samples/BluetoothLeGatt/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/BluetoothLeGatt/res/layout/gatt_services_characteristics.html" title="gatt_services_characteristics.xml">gatt_services_characteristics.xml</a></li><li><a href="/samples/BluetoothLeGatt/res/layout/listitem_device.html" title="listitem_device.xml">listitem_device.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/BluetoothLeGatt/res/menu/gatt_services.html" title="gatt_services.xml">gatt_services.xml</a></li><li><a href="/samples/BluetoothLeGatt/res/menu/main.html" title="main.xml">main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/BluetoothLeGatt/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/BluetoothLeGatt/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BluetoothLeGatt/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/BluetoothLeGatt/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/BluetoothLeGatt/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BluetoothLeGatt/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.bluetoothlegatt">com.example.android.bluetoothlegatt/</a></div><ul><li><a href="/samples/BluetoothLeGatt/src/com.example.android.bluetoothlegatt/BluetoothLeService.html" title="BluetoothLeService.java">BluetoothLeService.java</a></li><li><a href="/samples/BluetoothLeGatt/src/com.example.android.bluetoothlegatt/DeviceControlActivity.html" title="DeviceControlActivity.java">DeviceControlActivity.java</a></li><li><a href="/samples/BluetoothLeGatt/src/com.example.android.bluetoothlegatt/DeviceScanActivity.html" title="DeviceScanActivity.java">DeviceScanActivity.java</a></li><li><a href="/samples/BluetoothLeGatt/src/com.example.android.bluetoothlegatt/SampleGattAttributes.html" title="SampleGattAttributes.java">SampleGattAttributes.java</a></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/NetworkConnect/index.html" title="NetworkConnect">NetworkConnect</a></div><ul><li><a href="/samples/NetworkConnect/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/NetworkConnect/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/NetworkConnect/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/NetworkConnect/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/NetworkConnect/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/NetworkConnect/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/NetworkConnect/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/NetworkConnect/res/layout/sample_main.html" title="sample_main.xml">sample_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/NetworkConnect/res/menu/main.html" title="main.xml">main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/NetworkConnect/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/NetworkConnect/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/NetworkConnect/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/NetworkConnect/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/NetworkConnect/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/NetworkConnect/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common.logger">com.example.android.common.logger/</a></div><ul><li><a href="/samples/NetworkConnect/src/com.example.android.common.logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/NetworkConnect/src/com.example.android.common.logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/NetworkConnect/src/com.example.android.common.logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/NetworkConnect/src/com.example.android.common.logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/NetworkConnect/src/com.example.android.common.logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/NetworkConnect/src/com.example.android.common.logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.networkconnect">com.example.android.networkconnect/</a></div><ul><li><a href="/samples/NetworkConnect/src/com.example.android.networkconnect/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li><li><a href="/samples/NetworkConnect/src/com.example.android.networkconnect/SimpleTextFragment.html" title="SimpleTextFragment.java">SimpleTextFragment.java</a></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/BasicNetworking/index.html" title="BasicNetworking">BasicNetworking</a></div><ul><li><a href="/samples/BasicNetworking/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/BasicNetworking/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/BasicNetworking/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/BasicNetworking/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/BasicNetworking/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/BasicNetworking/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/BasicNetworking/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/BasicNetworking/res/layout/sample_main.html" title="sample_main.xml">sample_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/BasicNetworking/res/menu/main.html" title="main.xml">main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/BasicNetworking/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/BasicNetworking/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicNetworking/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/BasicNetworking/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/BasicNetworking/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicNetworking/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.basicnetworking">com.example.android.basicnetworking/</a></div><ul><li><a href="/samples/BasicNetworking/src/com.example.android.basicnetworking/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li><li><a href="/samples/BasicNetworking/src/com.example.android.basicnetworking/SimpleTextFragment.html" title="SimpleTextFragment.java">SimpleTextFragment.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common.logger">com.example.android.common.logger/</a></div><ul><li><a href="/samples/BasicNetworking/src/com.example.android.common.logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/BasicNetworking/src/com.example.android.common.logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/BasicNetworking/src/com.example.android.common.logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/BasicNetworking/src/com.example.android.common.logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/BasicNetworking/src/com.example.android.common.logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/BasicNetworking/src/com.example.android.common.logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/BasicSyncAdapter/index.html" title="BasicSyncAdapter">BasicSyncAdapter</a></div><ul><li><a href="/samples/BasicSyncAdapter/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/BasicSyncAdapter/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/BasicSyncAdapter/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/BasicSyncAdapter/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/BasicSyncAdapter/res/drawable-xhdpi/ic_action_refresh.html" title="ic_action_refresh.png">ic_action_refresh.png</a></li><li><a href="/samples/BasicSyncAdapter/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/BasicSyncAdapter/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/BasicSyncAdapter/res/layout/actionbar_indeterminate_progress.html" title="actionbar_indeterminate_progress.xml">actionbar_indeterminate_progress.xml</a></li><li><a href="/samples/BasicSyncAdapter/res/layout/activity_entry_list.html" title="activity_entry_list.xml">activity_entry_list.xml</a></li><li><a href="/samples/BasicSyncAdapter/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/BasicSyncAdapter/res/menu/main.html" title="main.xml">main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/BasicSyncAdapter/res/values/attrs.html" title="attrs.xml">attrs.xml</a></li><li><a href="/samples/BasicSyncAdapter/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/BasicSyncAdapter/res/values/dimen.html" title="dimen.xml">dimen.xml</a></li><li><a href="/samples/BasicSyncAdapter/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicSyncAdapter/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/BasicSyncAdapter/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/BasicSyncAdapter/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicSyncAdapter/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="xml">xml/</a></div><ul><li><a href="/samples/BasicSyncAdapter/res/xml/authenticator.html" title="authenticator.xml">authenticator.xml</a></li><li><a href="/samples/BasicSyncAdapter/res/xml/syncadapter.html" title="syncadapter.xml">syncadapter.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.basicsyncadapter">com.example.android.basicsyncadapter/</a></div><ul><li><a href="/samples/BasicSyncAdapter/src/com.example.android.basicsyncadapter/EntryListActivity.html" title="EntryListActivity.java">EntryListActivity.java</a></li><li><a href="/samples/BasicSyncAdapter/src/com.example.android.basicsyncadapter/EntryListFragment.html" title="EntryListFragment.java">EntryListFragment.java</a></li><li><a href="/samples/BasicSyncAdapter/src/com.example.android.basicsyncadapter/SyncAdapter.html" title="SyncAdapter.java">SyncAdapter.java</a></li><li><a href="/samples/BasicSyncAdapter/src/com.example.android.basicsyncadapter/SyncService.html" title="SyncService.java">SyncService.java</a></li><li><a href="/samples/BasicSyncAdapter/src/com.example.android.basicsyncadapter/SyncUtils.html" title="SyncUtils.java">SyncUtils.java</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="net">net/</a></div><ul><li><a href="/samples/BasicSyncAdapter/src/com.example.android.basicsyncadapter/net/FeedParser.html" title="FeedParser.java">FeedParser.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="provider">provider/</a></div><ul><li><a href="/samples/BasicSyncAdapter/src/com.example.android.basicsyncadapter/provider/FeedContract.html" title="FeedContract.java">FeedContract.java</a></li><li><a href="/samples/BasicSyncAdapter/src/com.example.android.basicsyncadapter/provider/FeedProvider.html" title="FeedProvider.java">FeedProvider.java</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common">com.example.android.common/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="accounts">accounts/</a></div><ul><li><a href="/samples/BasicSyncAdapter/src/com.example.android.common/accounts/GenericAccountService.html" title="GenericAccountService.java">GenericAccountService.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="db">db/</a></div><ul><li><a href="/samples/BasicSyncAdapter/src/com.example.android.common/db/SelectionBuilder.html" title="SelectionBuilder.java">SelectionBuilder.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="logger">logger/</a></div><ul><li><a href="/samples/BasicSyncAdapter/src/com.example.android.common/logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/BasicSyncAdapter/src/com.example.android.common/logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/BasicSyncAdapter/src/com.example.android.common/logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/BasicSyncAdapter/src/com.example.android.common/logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/BasicSyncAdapter/src/com.example.android.common/logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/BasicSyncAdapter/src/com.example.android.common/logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li></ul></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/content.html" title="Content">Content</a></div><ul><li class="nav-section"><div class="nav-section-header"><a href="/samples/BasicContactables/index.html" title="BasicContactables">BasicContactables</a></div><ul><li><a href="/samples/BasicContactables/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/BasicContactables/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/BasicContactables/res/drawable-hdpi/ic_search_api_holo_light.html" title="ic_search_api_holo_light.png">ic_search_api_holo_light.png</a></li><li><a href="/samples/BasicContactables/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/BasicContactables/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/BasicContactables/res/drawable-mdpi/ic_search_api_holo_light.html" title="ic_search_api_holo_light.png">ic_search_api_holo_light.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/BasicContactables/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/BasicContactables/res/drawable-xhdpi/ic_search_api_holo_light.html" title="ic_search_api_holo_light.png">ic_search_api_holo_light.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/BasicContactables/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/BasicContactables/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/BasicContactables/res/layout/sample_main.html" title="sample_main.xml">sample_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/BasicContactables/res/menu/main.html" title="main.xml">main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/BasicContactables/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/BasicContactables/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicContactables/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/BasicContactables/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/BasicContactables/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicContactables/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="xml">xml/</a></div><ul><li><a href="/samples/BasicContactables/res/xml/searchable.html" title="searchable.xml">searchable.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.basiccontactables">com.example.android.basiccontactables/</a></div><ul><li><a href="/samples/BasicContactables/src/com.example.android.basiccontactables/ContactablesLoaderCallbacks.html" title="ContactablesLoaderCallbacks.java">ContactablesLoaderCallbacks.java</a></li><li><a href="/samples/BasicContactables/src/com.example.android.basiccontactables/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common.logger">com.example.android.common.logger/</a></div><ul><li><a href="/samples/BasicContactables/src/com.example.android.common.logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/BasicContactables/src/com.example.android.common.logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/BasicContactables/src/com.example.android.common.logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/BasicContactables/src/com.example.android.common.logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/BasicContactables/src/com.example.android.common.logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/BasicContactables/src/com.example.android.common.logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/AppRestrictions/index.html" title="AppRestrictions">AppRestrictions</a></div><ul><li><a href="/samples/AppRestrictions/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/AppRestrictions/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/AppRestrictions/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/AppRestrictions/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/AppRestrictions/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/AppRestrictions/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/AppRestrictions/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/AppRestrictions/res/layout/main.html" title="main.xml">main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/AppRestrictions/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/AppRestrictions/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/AppRestrictions/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/AppRestrictions/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/AppRestrictions/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/AppRestrictions/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="xml">xml/</a></div><ul><li><a href="/samples/AppRestrictions/res/xml/custom_prefs.html" title="custom_prefs.xml">custom_prefs.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.apprestrictions">com.example.android.apprestrictions/</a></div><ul><li><a href="/samples/AppRestrictions/src/com.example.android.apprestrictions/CustomRestrictionsActivity.html" title="CustomRestrictionsActivity.java">CustomRestrictionsActivity.java</a></li><li><a href="/samples/AppRestrictions/src/com.example.android.apprestrictions/CustomRestrictionsFragment.html" title="CustomRestrictionsFragment.java">CustomRestrictionsFragment.java</a></li><li><a href="/samples/AppRestrictions/src/com.example.android.apprestrictions/GetRestrictionsReceiver.html" title="GetRestrictionsReceiver.java">GetRestrictionsReceiver.java</a></li><li><a href="/samples/AppRestrictions/src/com.example.android.apprestrictions/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/StorageClient/index.html" title="StorageClient">StorageClient</a></div><ul><li><a href="/samples/StorageClient/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/StorageClient/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/StorageClient/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/StorageClient/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/StorageClient/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/StorageClient/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/StorageClient/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/StorageClient/res/menu/main.html" title="main.xml">main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/StorageClient/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/StorageClient/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/StorageClient/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/StorageClient/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/StorageClient/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/StorageClient/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common">com.example.android.common/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="activities">activities/</a></div><ul><li><a href="/samples/StorageClient/src/com.example.android.common/activities/SampleActivityBase.html" title="SampleActivityBase.java">SampleActivityBase.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="logger">logger/</a></div><ul><li><a href="/samples/StorageClient/src/com.example.android.common/logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/StorageClient/src/com.example.android.common/logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/StorageClient/src/com.example.android.common/logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/StorageClient/src/com.example.android.common/logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/StorageClient/src/com.example.android.common/logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/StorageClient/src/com.example.android.common/logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.storageclient">com.example.android.storageclient/</a></div><ul><li><a href="/samples/StorageClient/src/com.example.android.storageclient/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li><li><a href="/samples/StorageClient/src/com.example.android.storageclient/StorageClientFragment.html" title="StorageClientFragment.java">StorageClientFragment.java</a></li></ul></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/input.html" title="Input">Input</a></div><ul><li class="nav-section"><div class="nav-section-header"><a href="/samples/BasicMultitouch/index.html" title="BasicMultitouch">BasicMultitouch</a></div><ul><li><a href="/samples/BasicMultitouch/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/BasicMultitouch/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/BasicMultitouch/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/BasicMultitouch/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/BasicMultitouch/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/BasicMultitouch/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/BasicMultitouch/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/BasicMultitouch/res/layout/layout_mainactivity.html" title="layout_mainactivity.xml">layout_mainactivity.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/BasicMultitouch/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/BasicMultitouch/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicMultitouch/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/BasicMultitouch/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/BasicMultitouch/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicMultitouch/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-v11">values-v11/</a></div><ul><li><a href="/samples/BasicMultitouch/res/values-v11/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-v14">values-v14/</a></div><ul><li><a href="/samples/BasicMultitouch/res/values-v14/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.basicmultitouch">com.example.android.basicmultitouch/</a></div><ul><li><a href="/samples/BasicMultitouch/src/com.example.android.basicmultitouch/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li><li><a href="/samples/BasicMultitouch/src/com.example.android.basicmultitouch/Pools.html" title="Pools.java">Pools.java</a></li><li><a href="/samples/BasicMultitouch/src/com.example.android.basicmultitouch/TouchDisplayView.html" title="TouchDisplayView.java">TouchDisplayView.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common.logger">com.example.android.common.logger/</a></div><ul><li><a href="/samples/BasicMultitouch/src/com.example.android.common.logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/BasicMultitouch/src/com.example.android.common.logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/BasicMultitouch/src/com.example.android.common.logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/BasicMultitouch/src/com.example.android.common.logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/BasicMultitouch/src/com.example.android.common.logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/BasicMultitouch/src/com.example.android.common.logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/BasicGestureDetect/index.html" title="BasicGestureDetect">BasicGestureDetect</a></div><ul><li><a href="/samples/BasicGestureDetect/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/BasicGestureDetect/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/BasicGestureDetect/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/BasicGestureDetect/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/BasicGestureDetect/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/BasicGestureDetect/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/BasicGestureDetect/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/BasicGestureDetect/res/menu/main.html" title="main.xml">main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/BasicGestureDetect/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/BasicGestureDetect/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicGestureDetect/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/BasicGestureDetect/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/BasicGestureDetect/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicGestureDetect/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.basicgesturedetect">com.example.android.basicgesturedetect/</a></div><ul><li><a href="/samples/BasicGestureDetect/src/com.example.android.basicgesturedetect/BasicGestureDetectFragment.html" title="BasicGestureDetectFragment.java">BasicGestureDetectFragment.java</a></li><li><a href="/samples/BasicGestureDetect/src/com.example.android.basicgesturedetect/GestureListener.html" title="GestureListener.java">GestureListener.java</a></li><li><a href="/samples/BasicGestureDetect/src/com.example.android.basicgesturedetect/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common">com.example.android.common/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="activities">activities/</a></div><ul><li><a href="/samples/BasicGestureDetect/src/com.example.android.common/activities/SampleActivityBase.html" title="SampleActivityBase.java">SampleActivityBase.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="logger">logger/</a></div><ul><li><a href="/samples/BasicGestureDetect/src/com.example.android.common/logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/BasicGestureDetect/src/com.example.android.common/logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/BasicGestureDetect/src/com.example.android.common/logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/BasicGestureDetect/src/com.example.android.common/logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/BasicGestureDetect/src/com.example.android.common/logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/BasicGestureDetect/src/com.example.android.common/logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li></ul></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/media.html" title="Media">Media</a></div><ul><li class="nav-section"><div class="nav-section-header"><a href="/samples/BasicMediaRouter/index.html" title="BasicMediaRouter">BasicMediaRouter</a></div><ul><li><a href="/samples/BasicMediaRouter/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/BasicMediaRouter/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/BasicMediaRouter/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/BasicMediaRouter/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/BasicMediaRouter/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/BasicMediaRouter/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/BasicMediaRouter/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/BasicMediaRouter/res/layout/display.html" title="display.xml">display.xml</a></li><li><a href="/samples/BasicMediaRouter/res/layout/sample_main.html" title="sample_main.xml">sample_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/BasicMediaRouter/res/menu/main.html" title="main.xml">main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/BasicMediaRouter/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/BasicMediaRouter/res/values/colors.html" title="colors.xml">colors.xml</a></li><li><a href="/samples/BasicMediaRouter/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicMediaRouter/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/BasicMediaRouter/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/BasicMediaRouter/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicMediaRouter/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.basicmediarouter">com.example.android.basicmediarouter/</a></div><ul><li><a href="/samples/BasicMediaRouter/src/com.example.android.basicmediarouter/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li><li><a href="/samples/BasicMediaRouter/src/com.example.android.basicmediarouter/SamplePresentation.html" title="SamplePresentation.java">SamplePresentation.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common.logger">com.example.android.common.logger/</a></div><ul><li><a href="/samples/BasicMediaRouter/src/com.example.android.common.logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/BasicMediaRouter/src/com.example.android.common.logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/BasicMediaRouter/src/com.example.android.common.logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/BasicMediaRouter/src/com.example.android.common.logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/BasicMediaRouter/src/com.example.android.common.logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/BasicMediaRouter/src/com.example.android.common.logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/BasicMediaDecoder/index.html" title="BasicMediaDecoder">BasicMediaDecoder</a></div><ul><li><a href="/samples/BasicMediaDecoder/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable">drawable/</a></div><ul><li><a href="/samples/BasicMediaDecoder/res/drawable/selector_play.html" title="selector_play.xml">selector_play.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/BasicMediaDecoder/res/drawable-hdpi/ic_action_play.html" title="ic_action_play.png">ic_action_play.png</a></li><li><a href="/samples/BasicMediaDecoder/res/drawable-hdpi/ic_action_play_disabled.html" title="ic_action_play_disabled.png">ic_action_play_disabled.png</a></li><li><a href="/samples/BasicMediaDecoder/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/BasicMediaDecoder/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/BasicMediaDecoder/res/drawable-mdpi/ic_action_play.html" title="ic_action_play.png">ic_action_play.png</a></li><li><a href="/samples/BasicMediaDecoder/res/drawable-mdpi/ic_action_play_disabled.html" title="ic_action_play_disabled.png">ic_action_play_disabled.png</a></li><li><a href="/samples/BasicMediaDecoder/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/BasicMediaDecoder/res/drawable-xhdpi/ic_action_play.html" title="ic_action_play.png">ic_action_play.png</a></li><li><a href="/samples/BasicMediaDecoder/res/drawable-xhdpi/ic_action_play_disabled.html" title="ic_action_play_disabled.png">ic_action_play_disabled.png</a></li><li><a href="/samples/BasicMediaDecoder/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/BasicMediaDecoder/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/BasicMediaDecoder/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/BasicMediaDecoder/res/layout/sample_main.html" title="sample_main.xml">sample_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/BasicMediaDecoder/res/menu/action_menu.html" title="action_menu.xml">action_menu.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="raw">raw/</a></div><ul><li>vid_bigbuckbunny.mp4</li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/BasicMediaDecoder/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/BasicMediaDecoder/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicMediaDecoder/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/BasicMediaDecoder/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/BasicMediaDecoder/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicMediaDecoder/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.basicmediadecoder">com.example.android.basicmediadecoder/</a></div><ul><li><a href="/samples/BasicMediaDecoder/src/com.example.android.basicmediadecoder/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common.media">com.example.android.common.media/</a></div><ul><li><a href="/samples/BasicMediaDecoder/src/com.example.android.common.media/CameraHelper.html" title="CameraHelper.java">CameraHelper.java</a></li><li><a href="/samples/BasicMediaDecoder/src/com.example.android.common.media/MediaCodecWrapper.html" title="MediaCodecWrapper.java">MediaCodecWrapper.java</a></li></ul></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/security.html" title="Security">Security</a></div><ul><li class="nav-section"><div class="nav-section-header"><a href="/samples/BasicAndroidKeyStore/index.html" title="BasicAndroidKeyStore">BasicAndroidKeyStore</a></div><ul><li><a href="/samples/BasicAndroidKeyStore/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/BasicAndroidKeyStore/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/BasicAndroidKeyStore/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/BasicAndroidKeyStore/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/BasicAndroidKeyStore/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/BasicAndroidKeyStore/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/BasicAndroidKeyStore/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/BasicAndroidKeyStore/res/menu/main.html" title="main.xml">main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/BasicAndroidKeyStore/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/BasicAndroidKeyStore/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicAndroidKeyStore/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/BasicAndroidKeyStore/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/BasicAndroidKeyStore/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicAndroidKeyStore/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.basicandroidkeystore">com.example.android.basicandroidkeystore/</a></div><ul><li><a href="/samples/BasicAndroidKeyStore/src/com.example.android.basicandroidkeystore/BasicAndroidKeyStoreFragment.html" title="BasicAndroidKeyStoreFragment.java">BasicAndroidKeyStoreFragment.java</a></li><li><a href="/samples/BasicAndroidKeyStore/src/com.example.android.basicandroidkeystore/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li><li><a href="/samples/BasicAndroidKeyStore/src/com.example.android.basicandroidkeystore/SecurityConstants.html" title="SecurityConstants.java">SecurityConstants.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common">com.example.android.common/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="activities">activities/</a></div><ul><li><a href="/samples/BasicAndroidKeyStore/src/com.example.android.common/activities/SampleActivityBase.html" title="SampleActivityBase.java">SampleActivityBase.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="logger">logger/</a></div><ul><li><a href="/samples/BasicAndroidKeyStore/src/com.example.android.common/logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/BasicAndroidKeyStore/src/com.example.android.common/logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/BasicAndroidKeyStore/src/com.example.android.common/logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/BasicAndroidKeyStore/src/com.example.android.common/logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/BasicAndroidKeyStore/src/com.example.android.common/logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/BasicAndroidKeyStore/src/com.example.android.common/logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li></ul></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/testing.html" title="Testing">Testing</a></div><ul><li class="nav-section"><div class="nav-section-header"><a href="/samples/ActivityInstrumentation/index.html" title="ActivityInstrumentation">ActivityInstrumentation</a></div><ul><li><a href="/samples/ActivityInstrumentation/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/ActivityInstrumentation/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/ActivityInstrumentation/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/ActivityInstrumentation/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/ActivityInstrumentation/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/ActivityInstrumentation/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/ActivityInstrumentation/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/ActivityInstrumentation/res/layout/sample_main.html" title="sample_main.xml">sample_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/ActivityInstrumentation/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/ActivityInstrumentation/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/ActivityInstrumentation/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/ActivityInstrumentation/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/ActivityInstrumentation/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/ActivityInstrumentation/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw720dp-land">values-sw720dp-land/</a></div><ul><li><a href="/samples/ActivityInstrumentation/res/values-sw720dp-land/dimens.html" title="dimens.xml">dimens.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.activityinstrumentation">com.example.android.activityinstrumentation/</a></div><ul><li><a href="/samples/ActivityInstrumentation/src/com.example.android.activityinstrumentation/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common.logger">com.example.android.common.logger/</a></div><ul><li><a href="/samples/ActivityInstrumentation/src/com.example.android.common.logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/ActivityInstrumentation/src/com.example.android.common.logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/ActivityInstrumentation/src/com.example.android.common.logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/ActivityInstrumentation/src/com.example.android.common.logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/ActivityInstrumentation/src/com.example.android.common.logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/ActivityInstrumentation/src/com.example.android.common.logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/ui.html" title="UI">UI</a></div><ul><li class="nav-section"><div class="nav-section-header"><a href="/samples/BasicAccessibility/index.html" title="BasicAccessibility">BasicAccessibility</a></div><ul><li><a href="/samples/BasicAccessibility/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/BasicAccessibility/res/drawable-hdpi/ic_action_discard.html" title="ic_action_discard.png">ic_action_discard.png</a></li><li><a href="/samples/BasicAccessibility/res/drawable-hdpi/ic_action_info.html" title="ic_action_info.png">ic_action_info.png</a></li><li><a href="/samples/BasicAccessibility/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/BasicAccessibility/res/drawable-hdpi/partly_cloudy.html" title="partly_cloudy.png">partly_cloudy.png</a></li><li><a href="/samples/BasicAccessibility/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/BasicAccessibility/res/drawable-mdpi/ic_action_discard.html" title="ic_action_discard.png">ic_action_discard.png</a></li><li><a href="/samples/BasicAccessibility/res/drawable-mdpi/ic_action_info.html" title="ic_action_info.png">ic_action_info.png</a></li><li><a href="/samples/BasicAccessibility/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/BasicAccessibility/res/drawable-xhdpi/ic_action_discard.html" title="ic_action_discard.png">ic_action_discard.png</a></li><li><a href="/samples/BasicAccessibility/res/drawable-xhdpi/ic_action_info.html" title="ic_action_info.png">ic_action_info.png</a></li><li><a href="/samples/BasicAccessibility/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/BasicAccessibility/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/BasicAccessibility/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/BasicAccessibility/res/layout/sample_main.html" title="sample_main.xml">sample_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/BasicAccessibility/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/BasicAccessibility/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicAccessibility/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/BasicAccessibility/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/BasicAccessibility/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicAccessibility/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw720dp-land">values-sw720dp-land/</a></div><ul><li><a href="/samples/BasicAccessibility/res/values-sw720dp-land/dimens.html" title="dimens.xml">dimens.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.basicaccessibility">com.example.android.basicaccessibility/</a></div><ul><li><a href="/samples/BasicAccessibility/src/com.example.android.basicaccessibility/DialView.html" title="DialView.java">DialView.java</a></li><li><a href="/samples/BasicAccessibility/src/com.example.android.basicaccessibility/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common.logger">com.example.android.common.logger/</a></div><ul><li><a href="/samples/BasicAccessibility/src/com.example.android.common.logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/BasicAccessibility/src/com.example.android.common.logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/BasicAccessibility/src/com.example.android.common.logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/BasicAccessibility/src/com.example.android.common.logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/BasicAccessibility/src/com.example.android.common.logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/BasicAccessibility/src/com.example.android.common.logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/HorizontalPaging/index.html" title="HorizontalPaging">HorizontalPaging</a></div><ul><li><a href="/samples/HorizontalPaging/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/HorizontalPaging/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/HorizontalPaging/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/HorizontalPaging/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/HorizontalPaging/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/HorizontalPaging/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/HorizontalPaging/res/layout/fragment_main_dummy.html" title="fragment_main_dummy.xml">fragment_main_dummy.xml</a></li><li><a href="/samples/HorizontalPaging/res/layout/sample_main.html" title="sample_main.xml">sample_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/HorizontalPaging/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/HorizontalPaging/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/HorizontalPaging/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/HorizontalPaging/res/values/styles.html" title="styles.xml">styles.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw720dp-land">values-sw720dp-land/</a></div><ul><li><a href="/samples/HorizontalPaging/res/values/values-sw720dp-land/dimens.html" title="dimens.xml">dimens.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/HorizontalPaging/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/HorizontalPaging/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.horizontalpaging">com.example.android.horizontalpaging/</a></div><ul><li><a href="/samples/HorizontalPaging/src/com.example.android.horizontalpaging/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/ShareActionProvider/index.html" title="ShareActionProvider">ShareActionProvider</a></div><ul><li><a href="/samples/ShareActionProvider/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/ShareActionProvider/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/ShareActionProvider/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/ShareActionProvider/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/ShareActionProvider/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/ShareActionProvider/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/ShareActionProvider/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/ShareActionProvider/res/layout/item_image.html" title="item_image.xml">item_image.xml</a></li><li><a href="/samples/ShareActionProvider/res/layout/item_text.html" title="item_text.xml">item_text.xml</a></li><li><a href="/samples/ShareActionProvider/res/layout/sample_main.html" title="sample_main.xml">sample_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/ShareActionProvider/res/menu/main_menu.html" title="main_menu.xml">main_menu.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/ShareActionProvider/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/ShareActionProvider/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/ShareActionProvider/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/ShareActionProvider/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/ShareActionProvider/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/ShareActionProvider/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.actionbarcompat.shareactionprovider">com.example.android.actionbarcompat.shareactionprovider/</a></div><ul><li><a href="/samples/ShareActionProvider/src/com.example.android.actionbarcompat.shareactionprovider/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="content">content/</a></div><ul><li><a href="/samples/ShareActionProvider/src/com.example.android.actionbarcompat.shareactionprovider/content/AssetProvider.html" title="AssetProvider.java">AssetProvider.java</a></li><li><a href="/samples/ShareActionProvider/src/com.example.android.actionbarcompat.shareactionprovider/content/ContentItem.html" title="ContentItem.java">ContentItem.java</a></li></ul></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/Styled/index.html" title="Styled">Styled</a></div><ul><li><a href="/samples/Styled/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable">drawable/</a></div><ul><li><a href="/samples/Styled/res/drawable/pressed_background.html" title="pressed_background.xml">pressed_background.xml</a></li><li><a href="/samples/Styled/res/drawable/progress_horizontal.html" title="progress_horizontal.xml">progress_horizontal.xml</a></li><li><a href="/samples/Styled/res/drawable/selectable_background.html" title="selectable_background.xml">selectable_background.xml</a></li><li><a href="/samples/Styled/res/drawable/spinner_background_ab.html" title="spinner_background_ab.xml">spinner_background_ab.xml</a></li><li><a href="/samples/Styled/res/drawable/tab_indicator_ab.html" title="tab_indicator_ab.xml">tab_indicator_ab.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/Styled/res/drawable-hdpi/ab_bottom_solid_styled.9.html" title="ab_bottom_solid_styled.9.png">ab_bottom_solid_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/ab_solid_styled.9.html" title="ab_solid_styled.9.png">ab_solid_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/ab_stacked_solid_styled.9.html" title="ab_stacked_solid_styled.9.png">ab_stacked_solid_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/ic_action_location.html" title="ic_action_location.png">ic_action_location.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/ic_action_refresh.html" title="ic_action_refresh.png">ic_action_refresh.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/ic_action_settings.html" title="ic_action_settings.png">ic_action_settings.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/list_focused_styled.9.html" title="list_focused_styled.9.png">list_focused_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/menu_dropdown_panel_styled.9.html" title="menu_dropdown_panel_styled.9.png">menu_dropdown_panel_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/progress_bg_styled.9.html" title="progress_bg_styled.9.png">progress_bg_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/progress_primary_styled.9.html" title="progress_primary_styled.9.png">progress_primary_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/progress_secondary_styled.9.html" title="progress_secondary_styled.9.png">progress_secondary_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/spinner_ab_default_styled.9.html" title="spinner_ab_default_styled.9.png">spinner_ab_default_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/spinner_ab_disabled_styled.9.html" title="spinner_ab_disabled_styled.9.png">spinner_ab_disabled_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/spinner_ab_focused_styled.9.html" title="spinner_ab_focused_styled.9.png">spinner_ab_focused_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/spinner_ab_pressed_styled.9.html" title="spinner_ab_pressed_styled.9.png">spinner_ab_pressed_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/tab_selected_focused_styled.9.html" title="tab_selected_focused_styled.9.png">tab_selected_focused_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/tab_selected_pressed_styled.9.html" title="tab_selected_pressed_styled.9.png">tab_selected_pressed_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/tab_selected_styled.9.html" title="tab_selected_styled.9.png">tab_selected_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/tab_unselected_focused_styled.9.html" title="tab_unselected_focused_styled.9.png">tab_unselected_focused_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/tab_unselected_pressed_styled.9.html" title="tab_unselected_pressed_styled.9.png">tab_unselected_pressed_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/Styled/res/drawable-mdpi/ab_bottom_solid_styled.9.html" title="ab_bottom_solid_styled.9.png">ab_bottom_solid_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/ab_solid_styled.9.html" title="ab_solid_styled.9.png">ab_solid_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/ab_stacked_solid_styled.9.html" title="ab_stacked_solid_styled.9.png">ab_stacked_solid_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/ic_action_location.html" title="ic_action_location.png">ic_action_location.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/ic_action_refresh.html" title="ic_action_refresh.png">ic_action_refresh.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/ic_action_settings.html" title="ic_action_settings.png">ic_action_settings.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/list_focused_styled.9.html" title="list_focused_styled.9.png">list_focused_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/menu_dropdown_panel_styled.9.html" title="menu_dropdown_panel_styled.9.png">menu_dropdown_panel_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/progress_bg_styled.9.html" title="progress_bg_styled.9.png">progress_bg_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/progress_primary_styled.9.html" title="progress_primary_styled.9.png">progress_primary_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/progress_secondary_styled.9.html" title="progress_secondary_styled.9.png">progress_secondary_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/spinner_ab_default_styled.9.html" title="spinner_ab_default_styled.9.png">spinner_ab_default_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/spinner_ab_disabled_styled.9.html" title="spinner_ab_disabled_styled.9.png">spinner_ab_disabled_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/spinner_ab_focused_styled.9.html" title="spinner_ab_focused_styled.9.png">spinner_ab_focused_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/spinner_ab_pressed_styled.9.html" title="spinner_ab_pressed_styled.9.png">spinner_ab_pressed_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/tab_selected_focused_styled.9.html" title="tab_selected_focused_styled.9.png">tab_selected_focused_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/tab_selected_pressed_styled.9.html" title="tab_selected_pressed_styled.9.png">tab_selected_pressed_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/tab_selected_styled.9.html" title="tab_selected_styled.9.png">tab_selected_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/tab_unselected_focused_styled.9.html" title="tab_unselected_focused_styled.9.png">tab_unselected_focused_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-mdpi/tab_unselected_pressed_styled.9.html" title="tab_unselected_pressed_styled.9.png">tab_unselected_pressed_styled.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/Styled/res/drawable-xhdpi/ab_bottom_solid_styled.9.html" title="ab_bottom_solid_styled.9.png">ab_bottom_solid_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/ab_solid_styled.9.html" title="ab_solid_styled.9.png">ab_solid_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/ab_stacked_solid_styled.9.html" title="ab_stacked_solid_styled.9.png">ab_stacked_solid_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/ic_action_location.html" title="ic_action_location.png">ic_action_location.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/ic_action_refresh.html" title="ic_action_refresh.png">ic_action_refresh.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/ic_action_settings.html" title="ic_action_settings.png">ic_action_settings.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/list_focused_styled.9.html" title="list_focused_styled.9.png">list_focused_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/menu_dropdown_panel_styled.9.html" title="menu_dropdown_panel_styled.9.png">menu_dropdown_panel_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/progress_bg_styled.9.html" title="progress_bg_styled.9.png">progress_bg_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/progress_primary_styled.9.html" title="progress_primary_styled.9.png">progress_primary_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/progress_secondary_styled.9.html" title="progress_secondary_styled.9.png">progress_secondary_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/spinner_ab_default_styled.9.html" title="spinner_ab_default_styled.9.png">spinner_ab_default_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/spinner_ab_disabled_styled.9.html" title="spinner_ab_disabled_styled.9.png">spinner_ab_disabled_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/spinner_ab_focused_styled.9.html" title="spinner_ab_focused_styled.9.png">spinner_ab_focused_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/spinner_ab_pressed_styled.9.html" title="spinner_ab_pressed_styled.9.png">spinner_ab_pressed_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/tab_selected_focused_styled.9.html" title="tab_selected_focused_styled.9.png">tab_selected_focused_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/tab_selected_pressed_styled.9.html" title="tab_selected_pressed_styled.9.png">tab_selected_pressed_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/tab_selected_styled.9.html" title="tab_selected_styled.9.png">tab_selected_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/tab_unselected_focused_styled.9.html" title="tab_unselected_focused_styled.9.png">tab_unselected_focused_styled.9.png</a></li><li><a href="/samples/Styled/res/drawable-xhdpi/tab_unselected_pressed_styled.9.html" title="tab_unselected_pressed_styled.9.png">tab_unselected_pressed_styled.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/Styled/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/Styled/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/Styled/res/layout/sample_main.html" title="sample_main.xml">sample_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/Styled/res/menu/main.html" title="main.xml">main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/Styled/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/Styled/res/values/colors.html" title="colors.xml">colors.xml</a></li><li><a href="/samples/Styled/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/Styled/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/Styled/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/Styled/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/Styled/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-v14">values-v14/</a></div><ul><li><a href="/samples/Styled/res/values-v14/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.actionbarcompat.styled">com.example.android.actionbarcompat.styled/</a></div><ul><li><a href="/samples/Styled/src/com.example.android.actionbarcompat.styled/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/Basic/index.html" title="Basic">Basic</a></div><ul><li><a href="/samples/Basic/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/Basic/res/drawable-hdpi/ic_action_location.html" title="ic_action_location.png">ic_action_location.png</a></li><li><a href="/samples/Basic/res/drawable-hdpi/ic_action_refresh.html" title="ic_action_refresh.png">ic_action_refresh.png</a></li><li><a href="/samples/Basic/res/drawable-hdpi/ic_action_settings.html" title="ic_action_settings.png">ic_action_settings.png</a></li><li><a href="/samples/Basic/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/Basic/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/Basic/res/drawable-mdpi/ic_action_location.html" title="ic_action_location.png">ic_action_location.png</a></li><li><a href="/samples/Basic/res/drawable-mdpi/ic_action_refresh.html" title="ic_action_refresh.png">ic_action_refresh.png</a></li><li><a href="/samples/Basic/res/drawable-mdpi/ic_action_settings.html" title="ic_action_settings.png">ic_action_settings.png</a></li><li><a href="/samples/Basic/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/Basic/res/drawable-xhdpi/ic_action_location.html" title="ic_action_location.png">ic_action_location.png</a></li><li><a href="/samples/Basic/res/drawable-xhdpi/ic_action_refresh.html" title="ic_action_refresh.png">ic_action_refresh.png</a></li><li><a href="/samples/Basic/res/drawable-xhdpi/ic_action_settings.html" title="ic_action_settings.png">ic_action_settings.png</a></li><li><a href="/samples/Basic/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/Basic/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/Basic/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/Basic/res/layout/sample_main.html" title="sample_main.xml">sample_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/Basic/res/menu/main.html" title="main.xml">main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/Basic/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/Basic/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/Basic/res/values/ids.html" title="ids.xml">ids.xml</a></li><li><a href="/samples/Basic/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/Basic/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/Basic/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/Basic/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.actionbarcompat.basic">com.example.android.actionbarcompat.basic/</a></div><ul><li><a href="/samples/Basic/src/com.example.android.actionbarcompat.basic/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/ImmersiveMode/index.html" title="ImmersiveMode">ImmersiveMode</a></div><ul><li><a href="/samples/ImmersiveMode/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/ImmersiveMode/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/ImmersiveMode/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/ImmersiveMode/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/ImmersiveMode/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/ImmersiveMode/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/ImmersiveMode/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/ImmersiveMode/res/menu/main.html" title="main.xml">main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/ImmersiveMode/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/ImmersiveMode/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/ImmersiveMode/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/ImmersiveMode/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/ImmersiveMode/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/ImmersiveMode/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common">com.example.android.common/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="activities">activities/</a></div><ul><li><a href="/samples/ImmersiveMode/src/com.example.android.common/activities/SampleActivityBase.html" title="SampleActivityBase.java">SampleActivityBase.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="logger">logger/</a></div><ul><li><a href="/samples/ImmersiveMode/src/com.example.android.common/logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/ImmersiveMode/src/com.example.android.common/logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/ImmersiveMode/src/com.example.android.common/logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/ImmersiveMode/src/com.example.android.common/logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/ImmersiveMode/src/com.example.android.common/logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/ImmersiveMode/src/com.example.android.common/logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.immersivemode">com.example.android.immersivemode/</a></div><ul><li><a href="/samples/ImmersiveMode/src/com.example.android.immersivemode/ImmersiveModeFragment.html" title="ImmersiveModeFragment.java">ImmersiveModeFragment.java</a></li><li><a href="/samples/ImmersiveMode/src/com.example.android.immersivemode/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/TextSwitcher/index.html" title="TextSwitcher">TextSwitcher</a></div><ul><li><a href="/samples/TextSwitcher/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/TextSwitcher/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/TextSwitcher/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/TextSwitcher/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/TextSwitcher/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/TextSwitcher/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/TextSwitcher/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/TextSwitcher/res/layout/sample_main.html" title="sample_main.xml">sample_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/TextSwitcher/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/TextSwitcher/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/TextSwitcher/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/TextSwitcher/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/TextSwitcher/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/TextSwitcher/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw720dp-land">values-sw720dp-land/</a></div><ul><li><a href="/samples/TextSwitcher/res/values-sw720dp-land/dimens.html" title="dimens.xml">dimens.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-v11">values-v11/</a></div><ul><li><a href="/samples/TextSwitcher/res/values-v11/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-v14">values-v14/</a></div><ul><li><a href="/samples/TextSwitcher/res/values-v14/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common.logger">com.example.android.common.logger/</a></div><ul><li><a href="/samples/TextSwitcher/src/com.example.android.common.logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/TextSwitcher/src/com.example.android.common.logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/TextSwitcher/src/com.example.android.common.logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/TextSwitcher/src/com.example.android.common.logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/TextSwitcher/src/com.example.android.common.logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/TextSwitcher/src/com.example.android.common.logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.textswitcher">com.example.android.textswitcher/</a></div><ul><li><a href="/samples/TextSwitcher/src/com.example.android.textswitcher/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/BorderlessButtons/index.html" title="BorderlessButtons">BorderlessButtons</a></div><ul><li><a href="/samples/BorderlessButtons/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/BorderlessButtons/res/drawable-hdpi/ic_action_delete.html" title="ic_action_delete.png">ic_action_delete.png</a></li><li><a href="/samples/BorderlessButtons/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/BorderlessButtons/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/BorderlessButtons/res/drawable-mdpi/ic_action_delete.html" title="ic_action_delete.png">ic_action_delete.png</a></li><li><a href="/samples/BorderlessButtons/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/BorderlessButtons/res/drawable-xhdpi/ic_action_delete.html" title="ic_action_delete.png">ic_action_delete.png</a></li><li><a href="/samples/BorderlessButtons/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/BorderlessButtons/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/BorderlessButtons/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/BorderlessButtons/res/layout/list_item.html" title="list_item.xml">list_item.xml</a></li><li><a href="/samples/BorderlessButtons/res/layout/sample_main.html" title="sample_main.xml">sample_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/BorderlessButtons/res/menu/main.html" title="main.xml">main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/BorderlessButtons/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/BorderlessButtons/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BorderlessButtons/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/BorderlessButtons/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/BorderlessButtons/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BorderlessButtons/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.borderlessbuttons">com.example.android.borderlessbuttons/</a></div><ul><li><a href="/samples/BorderlessButtons/src/com.example.android.borderlessbuttons/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common.logger">com.example.android.common.logger/</a></div><ul><li><a href="/samples/BorderlessButtons/src/com.example.android.common.logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/BorderlessButtons/src/com.example.android.common.logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/BorderlessButtons/src/com.example.android.common.logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/BorderlessButtons/src/com.example.android.common.logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/BorderlessButtons/src/com.example.android.common.logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/BorderlessButtons/src/com.example.android.common.logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/BasicNotifications/index.html" title="BasicNotifications">BasicNotifications</a></div><ul><li><a href="/samples/BasicNotifications/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/BasicNotifications/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/BasicNotifications/res/drawable-hdpi/ic_stat_notification.html" title="ic_stat_notification.png">ic_stat_notification.png</a></li><li><a href="/samples/BasicNotifications/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi-v11">drawable-hdpi-v11/</a></div><ul><li><a href="/samples/BasicNotifications/res/drawable-hdpi-v11/ic_stat_notification.html" title="ic_stat_notification.png">ic_stat_notification.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi-v9">drawable-hdpi-v9/</a></div><ul><li><a href="/samples/BasicNotifications/res/drawable-hdpi-v9/ic_stat_notification.html" title="ic_stat_notification.png">ic_stat_notification.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-ldpi-v11">drawable-ldpi-v11/</a></div><ul><li><a href="/samples/BasicNotifications/res/drawable-ldpi-v11/ic_stat_notification.html" title="ic_stat_notification.png">ic_stat_notification.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-ldpi-v9">drawable-ldpi-v9/</a></div><ul><li><a href="/samples/BasicNotifications/res/drawable-ldpi-v9/ic_stat_notification.html" title="ic_stat_notification.png">ic_stat_notification.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/BasicNotifications/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/BasicNotifications/res/drawable-mdpi/ic_stat_notification.html" title="ic_stat_notification.png">ic_stat_notification.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi-v11">drawable-mdpi-v11/</a></div><ul><li><a href="/samples/BasicNotifications/res/drawable-mdpi-v11/ic_stat_notification.html" title="ic_stat_notification.png">ic_stat_notification.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi-v9">drawable-mdpi-v9/</a></div><ul><li><a href="/samples/BasicNotifications/res/drawable-mdpi-v9/ic_stat_notification.html" title="ic_stat_notification.png">ic_stat_notification.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/BasicNotifications/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/BasicNotifications/res/drawable-xhdpi/ic_stat_notification.html" title="ic_stat_notification.png">ic_stat_notification.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi-v11">drawable-xhdpi-v11/</a></div><ul><li><a href="/samples/BasicNotifications/res/drawable-xhdpi-v11/ic_stat_notification.html" title="ic_stat_notification.png">ic_stat_notification.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi-v9">drawable-xhdpi-v9/</a></div><ul><li><a href="/samples/BasicNotifications/res/drawable-xhdpi-v9/ic_stat_notification.html" title="ic_stat_notification.png">ic_stat_notification.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/BasicNotifications/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/BasicNotifications/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/BasicNotifications/res/layout/sample_layout.html" title="sample_layout.xml">sample_layout.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/BasicNotifications/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/BasicNotifications/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicNotifications/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/BasicNotifications/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/BasicNotifications/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicNotifications/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.basicnotifications">com.example.android.basicnotifications/</a></div><ul><li><a href="/samples/BasicNotifications/src/com.example.android.basicnotifications/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/AdvancedImmersiveMode/index.html" title="AdvancedImmersiveMode">AdvancedImmersiveMode</a></div><ul><li><a href="/samples/AdvancedImmersiveMode/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/AdvancedImmersiveMode/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/AdvancedImmersiveMode/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/AdvancedImmersiveMode/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/AdvancedImmersiveMode/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/AdvancedImmersiveMode/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/AdvancedImmersiveMode/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/AdvancedImmersiveMode/res/menu/main.html" title="main.xml">main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/AdvancedImmersiveMode/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/AdvancedImmersiveMode/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/AdvancedImmersiveMode/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/AdvancedImmersiveMode/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/AdvancedImmersiveMode/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/AdvancedImmersiveMode/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.advancedimmersivemode">com.example.android.advancedimmersivemode/</a></div><ul><li><a href="/samples/AdvancedImmersiveMode/src/com.example.android.advancedimmersivemode/AdvancedImmersiveModeFragment.html" title="AdvancedImmersiveModeFragment.java">AdvancedImmersiveModeFragment.java</a></li><li><a href="/samples/AdvancedImmersiveMode/src/com.example.android.advancedimmersivemode/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common">com.example.android.common/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="activities">activities/</a></div><ul><li><a href="/samples/AdvancedImmersiveMode/src/com.example.android.common/activities/SampleActivityBase.html" title="SampleActivityBase.java">SampleActivityBase.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="logger">logger/</a></div><ul><li><a href="/samples/AdvancedImmersiveMode/src/com.example.android.common/logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/AdvancedImmersiveMode/src/com.example.android.common/logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/AdvancedImmersiveMode/src/com.example.android.common/logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/AdvancedImmersiveMode/src/com.example.android.common/logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/AdvancedImmersiveMode/src/com.example.android.common/logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/AdvancedImmersiveMode/src/com.example.android.common/logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/BasicImmersiveMode/index.html" title="BasicImmersiveMode">BasicImmersiveMode</a></div><ul><li><a href="/samples/BasicImmersiveMode/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/BasicImmersiveMode/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/BasicImmersiveMode/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/BasicImmersiveMode/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/BasicImmersiveMode/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/BasicImmersiveMode/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/BasicImmersiveMode/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/BasicImmersiveMode/res/menu/main.html" title="main.xml">main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/BasicImmersiveMode/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/BasicImmersiveMode/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicImmersiveMode/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/BasicImmersiveMode/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/BasicImmersiveMode/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/BasicImmersiveMode/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.basicimmersivemode">com.example.android.basicimmersivemode/</a></div><ul><li><a href="/samples/BasicImmersiveMode/src/com.example.android.basicimmersivemode/BasicImmersiveModeFragment.html" title="BasicImmersiveModeFragment.java">BasicImmersiveModeFragment.java</a></li><li><a href="/samples/BasicImmersiveMode/src/com.example.android.basicimmersivemode/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common">com.example.android.common/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="activities">activities/</a></div><ul><li><a href="/samples/BasicImmersiveMode/src/com.example.android.common/activities/SampleActivityBase.html" title="SampleActivityBase.java">SampleActivityBase.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="logger">logger/</a></div><ul><li><a href="/samples/BasicImmersiveMode/src/com.example.android.common/logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/BasicImmersiveMode/src/com.example.android.common/logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/BasicImmersiveMode/src/com.example.android.common/logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/BasicImmersiveMode/src/com.example.android.common/logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/BasicImmersiveMode/src/com.example.android.common/logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/BasicImmersiveMode/src/com.example.android.common/logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/CustomChoiceList/index.html" title="CustomChoiceList">CustomChoiceList</a></div><ul><li><a href="/samples/CustomChoiceList/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="color">color/</a></div><ul><li><a href="/samples/CustomChoiceList/res/color/hideable_text_color.html" title="hideable_text_color.xml">hideable_text_color.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable">drawable/</a></div><ul><li><a href="/samples/CustomChoiceList/res/drawable/ic_hideable_item.html" title="ic_hideable_item.xml">ic_hideable_item.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/CustomChoiceList/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/CustomChoiceList/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/CustomChoiceList/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/CustomChoiceList/res/drawable-xhdpi/ic_hideable_item_checked.html" title="ic_hideable_item_checked.png">ic_hideable_item_checked.png</a></li><li><a href="/samples/CustomChoiceList/res/drawable-xhdpi/ic_hideable_item_unchecked.html" title="ic_hideable_item_unchecked.png">ic_hideable_item_unchecked.png</a></li><li><a href="/samples/CustomChoiceList/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/CustomChoiceList/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/CustomChoiceList/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/CustomChoiceList/res/layout/list_item.html" title="list_item.xml">list_item.xml</a></li><li><a href="/samples/CustomChoiceList/res/layout/sample_main.html" title="sample_main.xml">sample_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/CustomChoiceList/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/CustomChoiceList/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/CustomChoiceList/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/CustomChoiceList/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/CustomChoiceList/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common.logger">com.example.android.common.logger/</a></div><ul><li><a href="/samples/CustomChoiceList/src/com.example.android.common.logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/CustomChoiceList/src/com.example.android.common.logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/CustomChoiceList/src/com.example.android.common.logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/CustomChoiceList/src/com.example.android.common.logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/CustomChoiceList/src/com.example.android.common.logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/CustomChoiceList/src/com.example.android.common.logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.customchoicelist">com.example.android.customchoicelist/</a></div><ul><li><a href="/samples/CustomChoiceList/src/com.example.android.customchoicelist/CheckableLinearLayout.html" title="CheckableLinearLayout.java">CheckableLinearLayout.java</a></li><li><a href="/samples/CustomChoiceList/src/com.example.android.customchoicelist/Cheeses.html" title="Cheeses.java">Cheeses.java</a></li><li><a href="/samples/CustomChoiceList/src/com.example.android.customchoicelist/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/DoneBar/index.html" title="DoneBar">DoneBar</a></div><ul><li><a href="/samples/DoneBar/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/DoneBar/res/drawable-hdpi/ic_action_cancel.html" title="ic_action_cancel.png">ic_action_cancel.png</a></li><li><a href="/samples/DoneBar/res/drawable-hdpi/ic_action_done.html" title="ic_action_done.png">ic_action_done.png</a></li><li><a href="/samples/DoneBar/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/DoneBar/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/DoneBar/res/drawable-mdpi/ic_action_cancel.html" title="ic_action_cancel.png">ic_action_cancel.png</a></li><li><a href="/samples/DoneBar/res/drawable-mdpi/ic_action_done.html" title="ic_action_done.png">ic_action_done.png</a></li><li><a href="/samples/DoneBar/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/DoneBar/res/drawable-xhdpi/ic_action_cancel.html" title="ic_action_cancel.png">ic_action_cancel.png</a></li><li><a href="/samples/DoneBar/res/drawable-xhdpi/ic_action_done.html" title="ic_action_done.png">ic_action_done.png</a></li><li><a href="/samples/DoneBar/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/DoneBar/res/drawable-xhdpi/sample_dashboard_item_background.9.html" title="sample_dashboard_item_background.9.png">sample_dashboard_item_background.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/DoneBar/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/DoneBar/res/layout/actionbar_custom_view_done.html" title="actionbar_custom_view_done.xml">actionbar_custom_view_done.xml</a></li><li><a href="/samples/DoneBar/res/layout/actionbar_custom_view_done_cancel.html" title="actionbar_custom_view_done_cancel.xml">actionbar_custom_view_done_cancel.xml</a></li><li><a href="/samples/DoneBar/res/layout/activity_done_bar.html" title="activity_done_bar.xml">activity_done_bar.xml</a></li><li><a href="/samples/DoneBar/res/layout/activity_done_button.html" title="activity_done_button.xml">activity_done_button.xml</a></li><li><a href="/samples/DoneBar/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/DoneBar/res/layout/activity_sample_dashboard.html" title="activity_sample_dashboard.xml">activity_sample_dashboard.xml</a></li><li><a href="/samples/DoneBar/res/layout/include_cancel_button.html" title="include_cancel_button.xml">include_cancel_button.xml</a></li><li><a href="/samples/DoneBar/res/layout/include_done_button.html" title="include_done_button.xml">include_done_button.xml</a></li><li><a href="/samples/DoneBar/res/layout/sample_dashboard_item.html" title="sample_dashboard_item.xml">sample_dashboard_item.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/DoneBar/res/menu/cancel.html" title="cancel.xml">cancel.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/DoneBar/res/values/activitycards-strings.html" title="activitycards-strings.xml">activitycards-strings.xml</a></li><li><a href="/samples/DoneBar/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/DoneBar/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/DoneBar/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/DoneBar/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/DoneBar/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/DoneBar/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.donebar">com.example.android.donebar/</a></div><ul><li><a href="/samples/DoneBar/src/com.example.android.donebar/DoneBarActivity.html" title="DoneBarActivity.java">DoneBarActivity.java</a></li><li><a href="/samples/DoneBar/src/com.example.android.donebar/DoneButtonActivity.html" title="DoneButtonActivity.java">DoneButtonActivity.java</a></li><li><a href="/samples/DoneBar/src/com.example.android.donebar/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/ListPopupMenu/index.html" title="ListPopupMenu">ListPopupMenu</a></div><ul><li><a href="/samples/ListPopupMenu/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/ListPopupMenu/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/ListPopupMenu/res/drawable-hdpi/ic_overflow.html" title="ic_overflow.png">ic_overflow.png</a></li><li><a href="/samples/ListPopupMenu/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/ListPopupMenu/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/ListPopupMenu/res/drawable-mdpi/ic_overflow.html" title="ic_overflow.png">ic_overflow.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/ListPopupMenu/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/ListPopupMenu/res/drawable-xhdpi/ic_overflow.html" title="ic_overflow.png">ic_overflow.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/ListPopupMenu/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/ListPopupMenu/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/ListPopupMenu/res/layout/list_item.html" title="list_item.xml">list_item.xml</a></li><li><a href="/samples/ListPopupMenu/res/layout/sample_main.html" title="sample_main.xml">sample_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="menu">menu/</a></div><ul><li><a href="/samples/ListPopupMenu/res/menu/popup.html" title="popup.xml">popup.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/ListPopupMenu/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/ListPopupMenu/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/ListPopupMenu/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/ListPopupMenu/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/ListPopupMenu/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/ListPopupMenu/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.actionbarcompat.listpopupmenu">com.example.android.actionbarcompat.listpopupmenu/</a></div><ul><li><a href="/samples/ListPopupMenu/src/com.example.android.actionbarcompat.listpopupmenu/Cheeses.html" title="Cheeses.java">Cheeses.java</a></li><li><a href="/samples/ListPopupMenu/src/com.example.android.actionbarcompat.listpopupmenu/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li><li><a href="/samples/ListPopupMenu/src/com.example.android.actionbarcompat.listpopupmenu/PopupListFragment.html" title="PopupListFragment.java">PopupListFragment.java</a></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/CustomNotifications/index.html" title="CustomNotifications">CustomNotifications</a></div><ul><li><a href="/samples/CustomNotifications/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/CustomNotifications/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/CustomNotifications/res/drawable-hdpi/ic_stat_custom.html" title="ic_stat_custom.png">ic_stat_custom.png</a></li><li><a href="/samples/CustomNotifications/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi-v11">drawable-hdpi-v11/</a></div><ul><li><a href="/samples/CustomNotifications/res/drawable-hdpi-v11/ic_stat_custom.html" title="ic_stat_custom.png">ic_stat_custom.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi-v9">drawable-hdpi-v9/</a></div><ul><li><a href="/samples/CustomNotifications/res/drawable-hdpi-v9/ic_stat_custom.html" title="ic_stat_custom.png">ic_stat_custom.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-ldpi-v11">drawable-ldpi-v11/</a></div><ul><li><a href="/samples/CustomNotifications/res/drawable-ldpi-v11/ic_stat_custom.html" title="ic_stat_custom.png">ic_stat_custom.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-ldpi-v9">drawable-ldpi-v9/</a></div><ul><li><a href="/samples/CustomNotifications/res/drawable-ldpi-v9/ic_stat_custom.html" title="ic_stat_custom.png">ic_stat_custom.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/CustomNotifications/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/CustomNotifications/res/drawable-mdpi/ic_stat_custom.html" title="ic_stat_custom.png">ic_stat_custom.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi-v11">drawable-mdpi-v11/</a></div><ul><li><a href="/samples/CustomNotifications/res/drawable-mdpi-v11/ic_stat_custom.html" title="ic_stat_custom.png">ic_stat_custom.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi-v9">drawable-mdpi-v9/</a></div><ul><li><a href="/samples/CustomNotifications/res/drawable-mdpi-v9/ic_stat_custom.html" title="ic_stat_custom.png">ic_stat_custom.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/CustomNotifications/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/CustomNotifications/res/drawable-xhdpi/ic_stat_custom.html" title="ic_stat_custom.png">ic_stat_custom.png</a></li><li><a href="/samples/CustomNotifications/res/drawable-xhdpi/robot.html" title="robot.png">robot.png</a></li><li><a href="/samples/CustomNotifications/res/drawable-xhdpi/robot_expanded.html" title="robot_expanded.png">robot_expanded.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi-v11">drawable-xhdpi-v11/</a></div><ul><li><a href="/samples/CustomNotifications/res/drawable-xhdpi-v11/ic_stat_custom.html" title="ic_stat_custom.png">ic_stat_custom.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi-v9">drawable-xhdpi-v9/</a></div><ul><li><a href="/samples/CustomNotifications/res/drawable-xhdpi-v9/ic_stat_custom.html" title="ic_stat_custom.png">ic_stat_custom.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/CustomNotifications/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/CustomNotifications/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/CustomNotifications/res/layout/notification.html" title="notification.xml">notification.xml</a></li><li><a href="/samples/CustomNotifications/res/layout/notification_expanded.html" title="notification_expanded.xml">notification_expanded.xml</a></li><li><a href="/samples/CustomNotifications/res/layout/sample_main.html" title="sample_main.xml">sample_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/CustomNotifications/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/CustomNotifications/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/CustomNotifications/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/CustomNotifications/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/CustomNotifications/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/CustomNotifications/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw720dp-land">values-sw720dp-land/</a></div><ul><li><a href="/samples/CustomNotifications/res/values-sw720dp-land/dimens.html" title="dimens.xml">dimens.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-v9">values-v9/</a></div><ul><li><a href="/samples/CustomNotifications/res/values-v9/styles.html" title="styles.xml">styles.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.customnotifications">com.example.android.customnotifications/</a></div><ul><li><a href="/samples/CustomNotifications/src/com.example.android.customnotifications/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li></ul></li></ul></li></ul></li><li class="nav-section"><div class="nav-section-header"><a href="/samples/views.html" title="Views">Views</a></div><ul><li class="nav-section"><div class="nav-section-header"><a href="/samples/TextLinkify/index.html" title="TextLinkify">TextLinkify</a></div><ul><li><a href="/samples/TextLinkify/AndroidManifest.html" title="AndroidManifest.xml">AndroidManifest.xml</a></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="res">res/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-hdpi">drawable-hdpi/</a></div><ul><li><a href="/samples/TextLinkify/res/drawable-hdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li><li><a href="/samples/TextLinkify/res/drawable-hdpi/tile.9.html" title="tile.9.png">tile.9.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-mdpi">drawable-mdpi/</a></div><ul><li><a href="/samples/TextLinkify/res/drawable-mdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xhdpi">drawable-xhdpi/</a></div><ul><li><a href="/samples/TextLinkify/res/drawable-xhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="drawable-xxhdpi">drawable-xxhdpi/</a></div><ul><li><a href="/samples/TextLinkify/res/drawable-xxhdpi/ic_launcher.html" title="ic_launcher.png">ic_launcher.png</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="layout">layout/</a></div><ul><li><a href="/samples/TextLinkify/res/layout/activity_main.html" title="activity_main.xml">activity_main.xml</a></li><li><a href="/samples/TextLinkify/res/layout/sample_main.html" title="sample_main.xml">sample_main.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values">values/</a></div><ul><li><a href="/samples/TextLinkify/res/values/base-strings.html" title="base-strings.xml">base-strings.xml</a></li><li><a href="/samples/TextLinkify/res/values/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/TextLinkify/res/values/strings.html" title="strings.xml">strings.xml</a></li><li><a href="/samples/TextLinkify/res/values/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw600dp">values-sw600dp/</a></div><ul><li><a href="/samples/TextLinkify/res/values-sw600dp/dimens.html" title="dimens.xml">dimens.xml</a></li><li><a href="/samples/TextLinkify/res/values-sw600dp/styles.html" title="styles.xml">styles.xml</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="values-sw720dp-land">values-sw720dp-land/</a></div><ul><li><a href="/samples/TextLinkify/res/values-sw720dp-land/dimens.html" title="dimens.xml">dimens.xml</a></li></ul></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="src">src/</a></div><ul><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.common.logger">com.example.android.common.logger/</a></div><ul><li><a href="/samples/TextLinkify/src/com.example.android.common.logger/Log.html" title="Log.java">Log.java</a></li><li><a href="/samples/TextLinkify/src/com.example.android.common.logger/LogFragment.html" title="LogFragment.java">LogFragment.java</a></li><li><a href="/samples/TextLinkify/src/com.example.android.common.logger/LogNode.html" title="LogNode.java">LogNode.java</a></li><li><a href="/samples/TextLinkify/src/com.example.android.common.logger/LogView.html" title="LogView.java">LogView.java</a></li><li><a href="/samples/TextLinkify/src/com.example.android.common.logger/LogWrapper.html" title="LogWrapper.java">LogWrapper.java</a></li><li><a href="/samples/TextLinkify/src/com.example.android.common.logger/MessageOnlyLogFilter.html" title="MessageOnlyLogFilter.java">MessageOnlyLogFilter.java</a></li></ul></li><li class="nav-section sticky"><div class="nav-section-header empty"><a href="#" onclick="return false;" title="com.example.android.textlinkify">com.example.android.textlinkify/</a></div><ul><li><a href="/samples/TextLinkify/src/com.example.android.textlinkify/MainActivity.html" title="MainActivity.java">MainActivity.java</a></li></ul></li></ul></li></ul></li></ul></li></ul>
 
diff --git a/docs/html/sdk/installing/studio.jd b/docs/html/sdk/installing/studio.jd
index f2fd79b..cba2346 100644
--- a/docs/html/sdk/installing/studio.jd
+++ b/docs/html/sdk/installing/studio.jd
@@ -294,7 +294,8 @@
 
 <p>If you already have Android Studio installed, in most cases, you can upgrade to the latest
 version by installing a patch. From within Android Studio, select
-<strong>Help &gt; Check for updates</strong> to see whether an update is available.</p>
+<strong>Help &gt; Check for updates</strong> (on Mac, <strong>Android Studio &gt;
+Check for updates</strong>) to see whether an update is available.</p>
 
 <p>If an update is not available,
 follow the <a href="#Installing">installation instructions</a> below and replace your existing
diff --git a/docs/html/tools/help/proguard.jd b/docs/html/tools/help/proguard.jd
index be0b8dc..3ba7db2 100644
--- a/docs/html/tools/help/proguard.jd
+++ b/docs/html/tools/help/proguard.jd
@@ -61,6 +61,12 @@
   <p>To enable ProGuard so that it runs as part of an Ant or Eclipse build, set the
   <code>proguard.config</code> property in the <code>&lt;project_root&gt;/project.properties</code>
   file. The path can be an absolute path or a path relative to the project's root.</p>
+
+<p class="note"><strong>Note:</strong> When using Android Studio, you must add Proguard
+to your <code>gradle.build</code> file's build types. For more information, see the
+<a href="http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Running-ProGuard"
+>Gradle Plugin User Guide</a>.
+
 <p>If you left the <code>proguard.cfg</code> file in its default location (the project's root directory),
 you can specify its location like this:</p>
 <pre class="no-pretty-print">
diff --git a/docs/html/tools/sdk/ndk/index.jd b/docs/html/tools/sdk/ndk/index.jd
index a418f90..87f8a87 100644
--- a/docs/html/tools/sdk/ndk/index.jd
+++ b/docs/html/tools/sdk/ndk/index.jd
@@ -2822,7 +2822,7 @@
   <p>Before you get started make sure that you have downloaded the latest <a href=
   "{@docRoot}sdk/index.html">Android SDK</a> and upgraded your applications and environment as
   needed. The NDK is compatible with older platform versions but not older versions of the SDK tools.
-  Also, take a moment to review the <a href="{@docRoot}tools/sdk/ndk/overview.html#reqs">System and
+  Also, take a moment to review the <a href="#Reqs">System and
 Software Requirements</a>
   for the NDK, if you haven't already.</p>
 
diff --git a/docs/html/training/beam-files/send-files.jd b/docs/html/training/beam-files/send-files.jd
index 917b87f..40f706f 100644
--- a/docs/html/training/beam-files/send-files.jd
+++ b/docs/html/training/beam-files/send-files.jd
@@ -139,7 +139,7 @@
 &lt;uses-feature android:name="android.hardware.nfc" android:required="false" /&gt;</pre>
 <p>
     If you set the attribute
-    <code><a href="guide/topics/manifest/uses-feature-element.html#required"
+    <code><a href="{@docRoot}guide/topics/manifest/uses-feature-element.html#required"
     >android:required</a>="false"</code>, you must test for NFC support and Android Beam file
     transfer support in code.
 </p>
diff --git a/docs/html/training/custom-views/create-view.jd b/docs/html/training/custom-views/create-view.jd
index b849cb3..11be85f 100644
--- a/docs/html/training/custom-views/create-view.jd
+++ b/docs/html/training/custom-views/create-view.jd
@@ -22,7 +22,7 @@
 
         <h2>You should also read</h2>
         <ul>
-            <li><a href="{@docRoot}/guide/topics/ui/custom-components.html">Custom Components</a>
+            <li><a href="{@docRoot}guide/topics/ui/custom-components.html">Custom Components</a>
             </li>
         </ul>
 <h2>Try it out</h2>
diff --git a/docs/html/training/gestures/scroll.jd b/docs/html/training/gestures/scroll.jd
index 09fcc4e..4b82d69 100644
--- a/docs/html/training/gestures/scroll.jd
+++ b/docs/html/training/gestures/scroll.jd
@@ -95,7 +95,7 @@
 finger across the touch screen. Simple dragging is often implemented by overriding 
 {@link android.view.GestureDetector.OnGestureListener#onScroll onScroll()} in 
 {@link android.view.GestureDetector.OnGestureListener}. For more discussion of dragging, see 
-<a href="dragging.html">Dragging and Scaling</a>.</li>
+<a href="scale.html">Dragging and Scaling</a>.</li>
 
     <li><strong>Flinging</strong> is the type of scrolling that occurs when a user 
 drags and lifts her finger quickly. After the user lifts her finger, you generally 
diff --git a/docs/html/training/location/location-testing.jd b/docs/html/training/location/location-testing.jd
index e36bac1..5021fc0 100644
--- a/docs/html/training/location/location-testing.jd
+++ b/docs/html/training/location/location-testing.jd
@@ -11,7 +11,7 @@
 <ol>
     <li><a href="#TurnOnMockMode">Turn On Mock Mode</a></li>
     <li><a href="#SendMockLocations">Send Mock Locations</a></li>
-    <li><a href="RunProvider">Run the Mock Location Provider App</a></li>
+    <li><a href="#RunProvider">Run the Mock Location Provider App</a></li>
     <li><a href="#TestingTips">Testing Tips</a>
 </ol>
 
@@ -62,7 +62,7 @@
     The best way to use mock locations is to send them from a separate mock location provider app.
     This lesson includes a provider app that you can download and use to test your own software.
     Modify the provider app as necessary to suit your own needs. Some ideas for providing test data
-    to the app are listed in the section <a href="TestData">Managing test data</a>.
+    to the app are listed in the section <a href="#TestData">Managing test data</a>.
 </p>
 <p>
     The remainder of this lesson shows you how to turn on mock mode and use a location client to
diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java
index af8441a..aac7876 100644
--- a/graphics/java/android/graphics/drawable/DrawableContainer.java
+++ b/graphics/java/android/graphics/drawable/DrawableContainer.java
@@ -88,9 +88,10 @@
     @Override
     public boolean getPadding(Rect padding) {
         final Rect r = mDrawableContainerState.getConstantPadding();
-        boolean result = true;
+        boolean result;
         if (r != null) {
             padding.set(r);
+            result = (r.left | r.top | r.bottom | r.right) != 0;
         } else {
             if (mCurrDrawable != null) {
                 result = mCurrDrawable.getPadding(padding);
diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
index ab34c0f..9c57a2c 100644
--- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java
+++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
@@ -244,7 +244,7 @@
         } else {
             padding.set(mPadding);
         }
-        return true;
+        return (padding.left | padding.top | padding.right | padding.bottom) != 0;
     }
 
     /**
diff --git a/graphics/java/android/graphics/pdf/PdfDocument.java b/graphics/java/android/graphics/pdf/PdfDocument.java
index 81e523d..29d14a2 100644
--- a/graphics/java/android/graphics/pdf/PdfDocument.java
+++ b/graphics/java/android/graphics/pdf/PdfDocument.java
@@ -18,6 +18,7 @@
 
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
+import android.graphics.Paint;
 import android.graphics.Rect;
 
 import dalvik.system.CloseGuard;
@@ -69,6 +70,12 @@
  */
 public class PdfDocument {
 
+    // TODO: We need a constructor that will take an OutputStream to
+    // support online data serialization as opposed to the current
+    // on demand one. The current approach is fine until Skia starts
+    // to support online PDF generation at which point we need to
+    // handle this.
+
     private final byte[] mChunk = new byte[4096];
 
     private final CloseGuard mCloseGuard = CloseGuard.get();
@@ -111,7 +118,7 @@
         if (pageInfo == null) {
             throw new IllegalArgumentException("page cannot be null");
         }
-        Canvas canvas = new PdfCanvas(nativeCreatePage(pageInfo.mPageWidth,
+        Canvas canvas = new PdfCanvas(nativeStartPage(mNativeDocument, pageInfo.mPageWidth,
                 pageInfo.mPageHeight, pageInfo.mContentRect.left, pageInfo.mContentRect.top,
                 pageInfo.mContentRect.right, pageInfo.mContentRect.bottom));
         mCurrentPage = new Page(canvas, pageInfo);
@@ -142,7 +149,7 @@
         }
         mPages.add(page.getInfo());
         mCurrentPage = null;
-        nativeAppendPage(mNativeDocument, page.mCanvas.mNativeCanvas);
+        nativeFinishPage(mNativeDocument);
         page.finish();
     }
 
@@ -204,7 +211,7 @@
 
     private void dispose() {
         if (mNativeDocument != 0) {
-            nativeFinalize(mNativeDocument);
+            nativeClose(mNativeDocument);
             mCloseGuard.close();
             mNativeDocument = 0;
         }
@@ -230,14 +237,14 @@
 
     private native int nativeCreateDocument();
 
-    private native void nativeFinalize(int document);
+    private native void nativeClose(int document);
 
-    private native void nativeAppendPage(int document, int page);
+    private native void nativeFinishPage(int document);
 
     private native void nativeWriteTo(int document, OutputStream out, byte[] chunk);
 
-    private static native int nativeCreatePage(int pageWidth, int pageHeight, int contentLeft,
-            int contentTop, int contentRight, int contentBottom);
+    private static native int nativeStartPage(int documentPtr, int pageWidth, int pageHeight,
+            int contentLeft, int contentTop, int contentRight, int contentBottom);
 
     private final class PdfCanvas extends Canvas {
 
@@ -392,28 +399,28 @@
          * Gets the {@link Canvas} of the page.
          *
          * <p>
-         * <strong>Note: </strong> There are some draw operations that are
-         * not yet supported by the canvas returned by this method. More
-         * specifically:
+         * <strong>Note: </strong> There are some draw operations that are not yet
+         * supported by the canvas returned by this method. More specifically:
          * <ul>
-         * <li>{@link Canvas#clipPath(android.graphics.Path)
-         *     Canvas.clipPath(android.graphics.Path)}</li>
-         * <li>All flavors of {@link Canvas#drawText(String, float, float,
-         *     android.graphics.Paint) Canvas.drawText(String, float, float,
-         *     android.graphics.Paint)}</li>
-         * <li>All flavors of {@link Canvas#drawPosText(String, float[],
-         *     android.graphics.Paint) Canvas.drawPosText(String, float[],
-         *     android.graphics.Paint)}</li>
+         * <li>Inverse path clipping performed via {@link Canvas#clipPath(android.graphics.Path,
+         *     android.graphics.Region.Op) Canvas.clipPath(android.graphics.Path,
+         *     android.graphics.Region.Op)} for {@link
+         *     android.graphics.Region.Op#REVERSE_DIFFERENCE
+         *     Region.Op#REVERSE_DIFFERENCE} operations.</li>
          * <li>{@link Canvas#drawVertices(android.graphics.Canvas.VertexMode, int,
          *     float[], int, float[], int, int[], int, short[], int, int,
          *     android.graphics.Paint) Canvas.drawVertices(
          *     android.graphics.Canvas.VertexMode, int, float[], int, float[],
          *     int, int[], int, short[], int, int, android.graphics.Paint)}</li>
-         * <li>{@link android.graphics.PorterDuff.Mode#SRC_ATOP PorterDuff.Mode SRC},
+         * <li>Color filters set via {@link Paint#setColorFilter(
+         *     android.graphics.ColorFilter)}</li>
+         * <li>Mask filters set via {@link Paint#setMaskFilter(
+         *     android.graphics.MaskFilter)}</li>
+         * <li>Some XFER modes such as
+         *     {@link android.graphics.PorterDuff.Mode#SRC_ATOP PorterDuff.Mode SRC},
          *     {@link android.graphics.PorterDuff.Mode#DST_ATOP PorterDuff.DST_ATOP},
          *     {@link android.graphics.PorterDuff.Mode#XOR PorterDuff.XOR},
          *     {@link android.graphics.PorterDuff.Mode#ADD PorterDuff.ADD}</li>
-         * <li>Perspective transforms</li>
          * </ul>
          *
          * @return The canvas if the page is not finished, null otherwise.
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 29030d2..aabfbd0 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -1074,7 +1074,13 @@
         }
     } else if (!rect.isEmpty()) {
         dirtyLayer(rect.left, rect.top, rect.right, rect.bottom);
+
+        save(0);
+        // the layer contains screen buffer content that shouldn't be alpha modulated
+        // (and any necessary alpha modulation was handled drawing into the layer)
+        mSnapshot->alpha = 1.0f;
         composeLayerRect(layer, rect, true);
+        restore();
     }
 
     dirtyClip();
diff --git a/media/java/android/media/IMediaRouterClient.aidl b/media/java/android/media/IMediaRouterClient.aidl
new file mode 100644
index 0000000..9640dcb
--- /dev/null
+++ b/media/java/android/media/IMediaRouterClient.aidl
@@ -0,0 +1,24 @@
+/*
+ * 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 android.media;
+
+/**
+ * {@hide}
+ */
+oneway interface IMediaRouterClient {
+    void onStateChanged();
+}
diff --git a/media/java/android/media/IMediaRouterService.aidl b/media/java/android/media/IMediaRouterService.aidl
new file mode 100644
index 0000000..f8f5fdf
--- /dev/null
+++ b/media/java/android/media/IMediaRouterService.aidl
@@ -0,0 +1,35 @@
+/*
+ * 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 android.media;
+
+import android.media.IMediaRouterClient;
+import android.media.MediaRouterClientState;
+
+/**
+ * {@hide}
+ */
+interface IMediaRouterService {
+    void registerClientAsUser(IMediaRouterClient client, String packageName, int userId);
+    void unregisterClient(IMediaRouterClient client);
+
+    MediaRouterClientState getState(IMediaRouterClient client);
+
+    void setDiscoveryRequest(IMediaRouterClient client, int routeTypes, boolean activeScan);
+    void setSelectedRoute(IMediaRouterClient client, String routeId, boolean explicit);
+    void requestSetVolume(IMediaRouterClient client, String routeId, int volume);
+    void requestUpdateVolume(IMediaRouterClient client, String routeId, int direction);
+}
diff --git a/media/java/android/media/IRemoteDisplayCallback.aidl b/media/java/android/media/IRemoteDisplayCallback.aidl
new file mode 100644
index 0000000..19cf070
--- /dev/null
+++ b/media/java/android/media/IRemoteDisplayCallback.aidl
@@ -0,0 +1,26 @@
+/*
+ * 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 android.media;
+
+import android.media.RemoteDisplayState;
+
+/**
+ * {@hide}
+ */
+oneway interface IRemoteDisplayCallback {
+    void onStateChanged(in RemoteDisplayState state);
+}
diff --git a/media/java/android/media/IRemoteDisplayProvider.aidl b/media/java/android/media/IRemoteDisplayProvider.aidl
new file mode 100644
index 0000000..b0d7379
--- /dev/null
+++ b/media/java/android/media/IRemoteDisplayProvider.aidl
@@ -0,0 +1,31 @@
+/*
+ * 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 android.media;
+
+import android.media.IRemoteDisplayCallback;
+
+/**
+ * {@hide}
+ */
+oneway interface IRemoteDisplayProvider {
+    void setCallback(in IRemoteDisplayCallback callback);
+    void setDiscoveryMode(int mode);
+    void connect(String id);
+    void disconnect(String id);
+    void setVolume(String id, int volume);
+    void adjustVolume(String id, int delta);
+}
diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java
index 9a79c94..c184e8f 100644
--- a/media/java/android/media/MediaRouter.java
+++ b/media/java/android/media/MediaRouter.java
@@ -16,6 +16,8 @@
 
 package android.media;
 
+import com.android.internal.util.Objects;
+
 import android.app.ActivityThread;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -30,6 +32,7 @@
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.UserHandle;
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.Display;
@@ -52,14 +55,17 @@
  */
 public class MediaRouter {
     private static final String TAG = "MediaRouter";
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
     static class Static implements DisplayManager.DisplayListener {
         // Time between wifi display scans when actively scanning in milliseconds.
         private static final int WIFI_DISPLAY_SCAN_INTERVAL = 15000;
 
+        final Context mAppContext;
         final Resources mResources;
         final IAudioService mAudioService;
         final DisplayManager mDisplayService;
+        final IMediaRouterService mMediaRouterService;
         final Handler mHandler;
         final CopyOnWriteArrayList<CallbackInfo> mCallbacks =
                 new CopyOnWriteArrayList<CallbackInfo>();
@@ -79,6 +85,13 @@
         WifiDisplayStatus mLastKnownWifiDisplayStatus;
         boolean mActivelyScanningWifiDisplays;
 
+        int mDiscoveryRequestRouteTypes;
+        boolean mDiscoverRequestActiveScan;
+
+        int mCurrentUserId = -1;
+        IMediaRouterClient mClient;
+        MediaRouterClientState mClientState;
+
         final IAudioRoutesObserver.Stub mAudioRoutesObserver = new IAudioRoutesObserver.Stub() {
             @Override
             public void dispatchAudioRoutesChanged(final AudioRoutesInfo newRoutes) {
@@ -101,6 +114,7 @@
         };
 
         Static(Context appContext) {
+            mAppContext = appContext;
             mResources = Resources.getSystem();
             mHandler = new Handler(appContext.getMainLooper());
 
@@ -109,6 +123,9 @@
 
             mDisplayService = (DisplayManager) appContext.getSystemService(Context.DISPLAY_SERVICE);
 
+            mMediaRouterService = IMediaRouterService.Stub.asInterface(
+                    ServiceManager.getService(Context.MEDIA_ROUTER_SERVICE));
+
             mSystemCategory = new RouteCategory(
                     com.android.internal.R.string.default_audio_route_category_name,
                     ROUTE_TYPE_LIVE_AUDIO | ROUTE_TYPE_LIVE_VIDEO, false);
@@ -146,10 +163,13 @@
                 updateAudioRoutes(newAudioRoutes);
             }
 
+            // Bind to the media router service.
+            rebindAsUser(UserHandle.myUserId());
+
             // Select the default route if the above didn't sync us up
             // appropriately with relevant system state.
             if (mSelectedRoute == null) {
-                selectRouteStatic(mDefaultAudioVideo.getSupportedTypes(), mDefaultAudioVideo);
+                selectDefaultRouteStatic();
             }
         }
 
@@ -197,7 +217,7 @@
                         dispatchRouteChanged(sStatic.mBluetoothA2dpRoute);
                     }
                 } else if (sStatic.mBluetoothA2dpRoute != null) {
-                    removeRoute(sStatic.mBluetoothA2dpRoute);
+                    removeRouteStatic(sStatic.mBluetoothA2dpRoute);
                     sStatic.mBluetoothA2dpRoute = null;
                 }
             }
@@ -205,16 +225,52 @@
             if (mBluetoothA2dpRoute != null) {
                 if (mainType != AudioRoutesInfo.MAIN_SPEAKER &&
                         mSelectedRoute == mBluetoothA2dpRoute && !a2dpEnabled) {
-                    selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO, mDefaultAudioVideo);
+                    selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO, mDefaultAudioVideo, false);
                 } else if ((mSelectedRoute == mDefaultAudioVideo || mSelectedRoute == null) &&
                         a2dpEnabled) {
-                    selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO, mBluetoothA2dpRoute);
+                    selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO, mBluetoothA2dpRoute, false);
                 }
             }
         }
 
-        void updateActiveScan() {
-            if (hasActiveScanCallbackOfType(ROUTE_TYPE_LIVE_VIDEO)) {
+        void updateDiscoveryRequest() {
+            // What are we looking for today?
+            int routeTypes = 0;
+            int passiveRouteTypes = 0;
+            boolean activeScan = false;
+            boolean activeScanWifiDisplay = false;
+            final int count = mCallbacks.size();
+            for (int i = 0; i < count; i++) {
+                CallbackInfo cbi = mCallbacks.get(i);
+                if ((cbi.flags & (CALLBACK_FLAG_PERFORM_ACTIVE_SCAN
+                        | CALLBACK_FLAG_REQUEST_DISCOVERY)) != 0) {
+                    // Discovery explicitly requested.
+                    routeTypes |= cbi.type;
+                } else if ((cbi.flags & CALLBACK_FLAG_PASSIVE_DISCOVERY) != 0) {
+                    // Discovery only passively requested.
+                    passiveRouteTypes |= cbi.type;
+                } else {
+                    // Legacy case since applications don't specify the discovery flag.
+                    // Unfortunately we just have to assume they always need discovery
+                    // whenever they have a callback registered.
+                    routeTypes |= cbi.type;
+                }
+                if ((cbi.flags & CALLBACK_FLAG_PERFORM_ACTIVE_SCAN) != 0) {
+                    activeScan = true;
+                    if ((cbi.type & (ROUTE_TYPE_LIVE_VIDEO | ROUTE_TYPE_REMOTE_DISPLAY)) != 0) {
+                        activeScanWifiDisplay = true;
+                    }
+                }
+            }
+            if (routeTypes != 0 || activeScan) {
+                // If someone else requests discovery then enable the passive listeners.
+                // This is used by the MediaRouteButton and MediaRouteActionProvider since
+                // they don't receive lifecycle callbacks from the Activity.
+                routeTypes |= passiveRouteTypes;
+            }
+
+            // Update wifi display scanning.
+            if (activeScanWifiDisplay) {
                 if (!mActivelyScanningWifiDisplays) {
                     mActivelyScanningWifiDisplays = true;
                     mHandler.post(mScanWifiDisplays);
@@ -225,18 +281,14 @@
                     mHandler.removeCallbacks(mScanWifiDisplays);
                 }
             }
-        }
 
-        private boolean hasActiveScanCallbackOfType(int type) {
-            final int count = mCallbacks.size();
-            for (int i = 0; i < count; i++) {
-                CallbackInfo cbi = mCallbacks.get(i);
-                if ((cbi.flags & CALLBACK_FLAG_PERFORM_ACTIVE_SCAN) != 0
-                        && (cbi.type & type) != 0) {
-                    return true;
-                }
+            // Tell the media router service all about it.
+            if (routeTypes != mDiscoveryRequestRouteTypes
+                    || activeScan != mDiscoverRequestActiveScan) {
+                mDiscoveryRequestRouteTypes = routeTypes;
+                mDiscoverRequestActiveScan = activeScan;
+                publishClientDiscoveryRequest();
             }
-            return false;
         }
 
         @Override
@@ -271,6 +323,270 @@
                 }
             }
         }
+
+        void setSelectedRoute(RouteInfo info, boolean explicit) {
+            // Must be non-reentrant.
+            mSelectedRoute = info;
+            publishClientSelectedRoute(explicit);
+        }
+
+        void rebindAsUser(int userId) {
+            if (mCurrentUserId != userId || userId < 0 || mClient == null) {
+                if (mClient != null) {
+                    try {
+                        mMediaRouterService.unregisterClient(mClient);
+                    } catch (RemoteException ex) {
+                        Log.e(TAG, "Unable to unregister media router client.", ex);
+                    }
+                    mClient = null;
+                }
+
+                mCurrentUserId = userId;
+
+                try {
+                    Client client = new Client();
+                    mMediaRouterService.registerClientAsUser(client,
+                            mAppContext.getPackageName(), userId);
+                    mClient = client;
+                } catch (RemoteException ex) {
+                    Log.e(TAG, "Unable to register media router client.", ex);
+                }
+
+                publishClientDiscoveryRequest();
+                publishClientSelectedRoute(false);
+                updateClientState();
+            }
+        }
+
+        void publishClientDiscoveryRequest() {
+            if (mClient != null) {
+                try {
+                    mMediaRouterService.setDiscoveryRequest(mClient,
+                            mDiscoveryRequestRouteTypes, mDiscoverRequestActiveScan);
+                } catch (RemoteException ex) {
+                    Log.e(TAG, "Unable to publish media router client discovery request.", ex);
+                }
+            }
+        }
+
+        void publishClientSelectedRoute(boolean explicit) {
+            if (mClient != null) {
+                try {
+                    mMediaRouterService.setSelectedRoute(mClient,
+                            mSelectedRoute != null ? mSelectedRoute.mGlobalRouteId : null,
+                            explicit);
+                } catch (RemoteException ex) {
+                    Log.e(TAG, "Unable to publish media router client selected route.", ex);
+                }
+            }
+        }
+
+        void updateClientState() {
+            // Update the client state.
+            mClientState = null;
+            if (mClient != null) {
+                try {
+                    mClientState = mMediaRouterService.getState(mClient);
+                } catch (RemoteException ex) {
+                    Log.e(TAG, "Unable to retrieve media router client state.", ex);
+                }
+            }
+            final ArrayList<MediaRouterClientState.RouteInfo> globalRoutes =
+                    mClientState != null ? mClientState.routes : null;
+            final String globallySelectedRouteId = mClientState != null ?
+                    mClientState.globallySelectedRouteId : null;
+
+            // Add or update routes.
+            final int globalRouteCount = globalRoutes != null ? globalRoutes.size() : 0;
+            for (int i = 0; i < globalRouteCount; i++) {
+                final MediaRouterClientState.RouteInfo globalRoute = globalRoutes.get(i);
+                RouteInfo route = findGlobalRoute(globalRoute.id);
+                if (route == null) {
+                    route = makeGlobalRoute(globalRoute);
+                    addRouteStatic(route);
+                } else {
+                    updateGlobalRoute(route, globalRoute);
+                }
+            }
+
+            // Synchronize state with the globally selected route.
+            if (globallySelectedRouteId != null) {
+                final RouteInfo route = findGlobalRoute(globallySelectedRouteId);
+                if (route == null) {
+                    Log.w(TAG, "Could not find new globally selected route: "
+                            + globallySelectedRouteId);
+                } else if (route != mSelectedRoute) {
+                    if (DEBUG) {
+                        Log.d(TAG, "Selecting new globally selected route: " + route);
+                    }
+                    selectRouteStatic(route.mSupportedTypes, route, false);
+                }
+            } else if (mSelectedRoute != null && mSelectedRoute.mGlobalRouteId != null) {
+                if (DEBUG) {
+                    Log.d(TAG, "Unselecting previous globally selected route: " + mSelectedRoute);
+                }
+                selectDefaultRouteStatic();
+            }
+
+            // Remove defunct routes.
+            outer: for (int i = mRoutes.size(); i-- > 0; ) {
+                final RouteInfo route = mRoutes.get(i);
+                final String globalRouteId = route.mGlobalRouteId;
+                if (globalRouteId != null) {
+                    for (int j = 0; j < globalRouteCount; j++) {
+                        MediaRouterClientState.RouteInfo globalRoute = globalRoutes.get(j);
+                        if (globalRouteId.equals(globalRoute.id)) {
+                            continue outer; // found
+                        }
+                    }
+                    // not found
+                    removeRouteStatic(route);
+                }
+            }
+        }
+
+        void requestSetVolume(RouteInfo route, int volume) {
+            if (route.mGlobalRouteId != null && mClient != null) {
+                try {
+                    mMediaRouterService.requestSetVolume(mClient,
+                            route.mGlobalRouteId, volume);
+                } catch (RemoteException ex) {
+                    Log.w(TAG, "Unable to request volume change.", ex);
+                }
+            }
+        }
+
+        void requestUpdateVolume(RouteInfo route, int direction) {
+            if (route.mGlobalRouteId != null && mClient != null) {
+                try {
+                    mMediaRouterService.requestUpdateVolume(mClient,
+                            route.mGlobalRouteId, direction);
+                } catch (RemoteException ex) {
+                    Log.w(TAG, "Unable to request volume change.", ex);
+                }
+            }
+        }
+
+        RouteInfo makeGlobalRoute(MediaRouterClientState.RouteInfo globalRoute) {
+            RouteInfo route = new RouteInfo(sStatic.mSystemCategory);
+            route.mGlobalRouteId = globalRoute.id;
+            route.mName = globalRoute.name;
+            route.mDescription = globalRoute.description;
+            route.mSupportedTypes = globalRoute.supportedTypes;
+            route.mEnabled = globalRoute.enabled;
+            route.setStatusCode(globalRoute.statusCode);
+            route.mPlaybackType = globalRoute.playbackType;
+            route.mPlaybackStream = globalRoute.playbackStream;
+            route.mVolume = globalRoute.volume;
+            route.mVolumeMax = globalRoute.volumeMax;
+            route.mVolumeHandling = globalRoute.volumeHandling;
+            route.mPresentationDisplay = getDisplayForGlobalRoute(globalRoute);
+            return route;
+        }
+
+        void updateGlobalRoute(RouteInfo route, MediaRouterClientState.RouteInfo globalRoute) {
+            boolean changed = false;
+            boolean volumeChanged = false;
+            boolean presentationDisplayChanged = false;
+
+            if (!Objects.equal(route.mName, globalRoute.name)) {
+                route.mName = globalRoute.name;
+                changed = true;
+            }
+            if (!Objects.equal(route.mDescription, globalRoute.description)) {
+                route.mDescription = globalRoute.description;
+                changed = true;
+            }
+            if (route.mSupportedTypes != globalRoute.supportedTypes) {
+                route.mSupportedTypes = globalRoute.supportedTypes;
+                changed = true;
+            }
+            if (route.mEnabled != globalRoute.enabled) {
+                route.mEnabled = globalRoute.enabled;
+                changed = true;
+            }
+            if (route.mStatusCode != globalRoute.statusCode) {
+                route.setStatusCode(globalRoute.statusCode);
+                changed = true;
+            }
+            if (route.mPlaybackType != globalRoute.playbackType) {
+                route.mPlaybackType = globalRoute.playbackType;
+                changed = true;
+            }
+            if (route.mPlaybackStream != globalRoute.playbackStream) {
+                route.mPlaybackStream = globalRoute.playbackStream;
+                changed = true;
+            }
+            if (route.mVolume != globalRoute.volume) {
+                route.mVolume = globalRoute.volume;
+                changed = true;
+                volumeChanged = true;
+            }
+            if (route.mVolumeMax != globalRoute.volumeMax) {
+                route.mVolumeMax = globalRoute.volumeMax;
+                changed = true;
+                volumeChanged = true;
+            }
+            if (route.mVolumeHandling != globalRoute.volumeHandling) {
+                route.mVolumeHandling = globalRoute.volumeHandling;
+                changed = true;
+                volumeChanged = true;
+            }
+            final Display presentationDisplay = getDisplayForGlobalRoute(globalRoute);
+            if (route.mPresentationDisplay != presentationDisplay) {
+                route.mPresentationDisplay = presentationDisplay;
+                changed = true;
+                presentationDisplayChanged = true;
+            }
+
+            if (changed) {
+                dispatchRouteChanged(route);
+            }
+            if (volumeChanged) {
+                dispatchRouteVolumeChanged(route);
+            }
+            if (presentationDisplayChanged) {
+                dispatchRoutePresentationDisplayChanged(route);
+            }
+        }
+
+        Display getDisplayForGlobalRoute(MediaRouterClientState.RouteInfo globalRoute) {
+            // Ensure that the specified display is valid for presentations.
+            // This check will normally disallow the default display unless it was configured
+            // as a presentation display for some reason.
+            if (globalRoute.presentationDisplayId >= 0) {
+                Display display = mDisplayService.getDisplay(globalRoute.presentationDisplayId);
+                if (display != null && display.isPublicPresentation()) {
+                    return display;
+                }
+            }
+            return null;
+        }
+
+        RouteInfo findGlobalRoute(String globalRouteId) {
+            final int count = mRoutes.size();
+            for (int i = 0; i < count; i++) {
+                final RouteInfo route = mRoutes.get(i);
+                if (globalRouteId.equals(route.mGlobalRouteId)) {
+                    return route;
+                }
+            }
+            return null;
+        }
+
+        final class Client extends IMediaRouterClient.Stub {
+            @Override
+            public void onStateChanged() {
+                mHandler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        if (Client.this == mClient) {
+                            updateClientState();
+                        }
+                    }
+                });
+            }
+        }
     }
 
     static Static sStatic;
@@ -285,7 +601,7 @@
      * <p>Once initiated this routing is transparent to the application. All audio
      * played on the media stream will be routed to the selected destination.</p>
      */
-    public static final int ROUTE_TYPE_LIVE_AUDIO = 0x1;
+    public static final int ROUTE_TYPE_LIVE_AUDIO = 1 << 0;
 
     /**
      * Route type flag for live video.
@@ -302,7 +618,13 @@
      * @see RouteInfo#getPresentationDisplay()
      * @see android.app.Presentation
      */
-    public static final int ROUTE_TYPE_LIVE_VIDEO = 0x2;
+    public static final int ROUTE_TYPE_LIVE_VIDEO = 1 << 1;
+
+    /**
+     * Temporary interop constant to identify remote displays.
+     * @hide To be removed when media router API is updated.
+     */
+    public static final int ROUTE_TYPE_REMOTE_DISPLAY = 1 << 2;
 
     /**
      * Route type flag for application-specific usage.
@@ -312,7 +634,10 @@
      * is expected to interpret the meaning of these events and perform the requested
      * routing tasks.</p>
      */
-    public static final int ROUTE_TYPE_USER = 0x00800000;
+    public static final int ROUTE_TYPE_USER = 1 << 23;
+
+    static final int ROUTE_TYPE_ANY = ROUTE_TYPE_LIVE_AUDIO | ROUTE_TYPE_LIVE_VIDEO
+            | ROUTE_TYPE_REMOTE_DISPLAY | ROUTE_TYPE_USER;
 
     /**
      * Flag for {@link #addCallback}: Actively scan for routes while this callback
@@ -336,11 +661,27 @@
      * Flag for {@link #addCallback}: Do not filter route events.
      * <p>
      * When this flag is specified, the callback will be invoked for event that affect any
-     * route event if they do not match the callback's associated media route selector.
+     * route even if they do not match the callback's filter.
      * </p>
      */
     public static final int CALLBACK_FLAG_UNFILTERED_EVENTS = 1 << 1;
 
+    /**
+     * Explicitly requests discovery.
+     *
+     * @hide Future API ported from support library.  Revisit this later.
+     */
+    public static final int CALLBACK_FLAG_REQUEST_DISCOVERY = 1 << 2;
+
+    /**
+     * Requests that discovery be performed but only if there is some other active
+     * callback already registered.
+     *
+     * @hide Compatibility workaround for the fact that applications do not currently
+     * request discovery explicitly (except when using the support library API).
+     */
+    public static final int CALLBACK_FLAG_PASSIVE_DISCOVERY = 1 << 3;
+
     // Maps application contexts
     static final HashMap<Context, MediaRouter> sRouters = new HashMap<Context, MediaRouter>();
 
@@ -352,6 +693,9 @@
         if ((types & ROUTE_TYPE_LIVE_VIDEO) != 0) {
             result.append("ROUTE_TYPE_LIVE_VIDEO ");
         }
+        if ((types & ROUTE_TYPE_REMOTE_DISPLAY) != 0) {
+            result.append("ROUTE_TYPE_REMOTE_DISPLAY ");
+        }
         if ((types & ROUTE_TYPE_USER) != 0) {
             result.append("ROUTE_TYPE_USER ");
         }
@@ -453,9 +797,7 @@
             info = new CallbackInfo(cb, types, flags, this);
             sStatic.mCallbacks.add(info);
         }
-        if ((info.flags & CALLBACK_FLAG_PERFORM_ACTIVE_SCAN) != 0) {
-            sStatic.updateActiveScan();
-        }
+        sStatic.updateDiscoveryRequest();
     }
 
     /**
@@ -466,10 +808,8 @@
     public void removeCallback(Callback cb) {
         int index = findCallbackInfo(cb);
         if (index >= 0) {
-            CallbackInfo info = sStatic.mCallbacks.remove(index);
-            if ((info.flags & CALLBACK_FLAG_PERFORM_ACTIVE_SCAN) != 0) {
-                sStatic.updateActiveScan();
-            }
+            sStatic.mCallbacks.remove(index);
+            sStatic.updateDiscoveryRequest();
         } else {
             Log.w(TAG, "removeCallback(" + cb + "): callback not registered");
         }
@@ -499,17 +839,17 @@
      * @param route Route to select
      */
     public void selectRoute(int types, RouteInfo route) {
-        selectRouteStatic(types, route);
+        selectRouteStatic(types, route, true);
     }
-    
+
     /**
      * @hide internal use
      */
-    public void selectRouteInt(int types, RouteInfo route) {
-        selectRouteStatic(types, route);
+    public void selectRouteInt(int types, RouteInfo route, boolean explicit) {
+        selectRouteStatic(types, route, explicit);
     }
 
-    static void selectRouteStatic(int types, RouteInfo route) {
+    static void selectRouteStatic(int types, RouteInfo route, boolean explicit) {
         final RouteInfo oldRoute = sStatic.mSelectedRoute;
         if (oldRoute == route) return;
         if ((route.getSupportedTypes() & types) == 0) {
@@ -541,15 +881,26 @@
             }
         }
 
+        sStatic.setSelectedRoute(route, explicit);
+
         if (oldRoute != null) {
             dispatchRouteUnselected(types & oldRoute.getSupportedTypes(), oldRoute);
         }
-        sStatic.mSelectedRoute = route;
         if (route != null) {
             dispatchRouteSelected(types & route.getSupportedTypes(), route);
         }
     }
 
+    static void selectDefaultRouteStatic() {
+        // TODO: Be smarter about the route types here; this selects for all valid.
+        if (sStatic.mSelectedRoute != sStatic.mBluetoothA2dpRoute
+                && sStatic.mBluetoothA2dpRoute != null) {
+            selectRouteStatic(ROUTE_TYPE_ANY, sStatic.mBluetoothA2dpRoute, false);
+        } else {
+            selectRouteStatic(ROUTE_TYPE_ANY, sStatic.mDefaultAudioVideo, false);
+        }
+    }
+
     /**
      * Compare the device address of a display and a route.
      * Nulls/no device address will match another null/no address.
@@ -612,7 +963,7 @@
      * @see #addUserRoute(UserRouteInfo)
      */
     public void removeUserRoute(UserRouteInfo info) {
-        removeRoute(info);
+        removeRouteStatic(info);
     }
 
     /**
@@ -626,7 +977,7 @@
             // TODO Right now, RouteGroups only ever contain user routes.
             // The code below will need to change if this assumption does.
             if (info instanceof UserRouteInfo || info instanceof RouteGroup) {
-                removeRouteAt(i);
+                removeRouteStatic(info);
                 i--;
             }
         }
@@ -636,10 +987,10 @@
      * @hide internal use only
      */
     public void removeRouteInt(RouteInfo info) {
-        removeRoute(info);
+        removeRouteStatic(info);
     }
 
-    static void removeRoute(RouteInfo info) {
+    static void removeRouteStatic(RouteInfo info) {
         if (sStatic.mRoutes.remove(info)) {
             final RouteCategory removingCat = info.getCategory();
             final int count = sStatic.mRoutes.size();
@@ -653,40 +1004,7 @@
             }
             if (info == sStatic.mSelectedRoute) {
                 // Removing the currently selected route? Select the default before we remove it.
-                // TODO: Be smarter about the route types here; this selects for all valid.
-                if (info != sStatic.mBluetoothA2dpRoute && sStatic.mBluetoothA2dpRoute != null) {
-                    selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO | ROUTE_TYPE_USER,
-                            sStatic.mBluetoothA2dpRoute);
-                } else {
-                    selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO | ROUTE_TYPE_USER,
-                            sStatic.mDefaultAudioVideo);
-                }
-            }
-            if (!found) {
-                sStatic.mCategories.remove(removingCat);
-            }
-            dispatchRouteRemoved(info);
-        }
-    }
-
-    void removeRouteAt(int routeIndex) {
-        if (routeIndex >= 0 && routeIndex < sStatic.mRoutes.size()) {
-            final RouteInfo info = sStatic.mRoutes.remove(routeIndex);
-            final RouteCategory removingCat = info.getCategory();
-            final int count = sStatic.mRoutes.size();
-            boolean found = false;
-            for (int i = 0; i < count; i++) {
-                final RouteCategory cat = sStatic.mRoutes.get(i).getCategory();
-                if (removingCat == cat) {
-                    found = true;
-                    break;
-                }
-            }
-            if (info == sStatic.mSelectedRoute) {
-                // Removing the currently selected route? Select the default before we remove it.
-                // TODO: Be smarter about the route types here; this selects for all valid.
-                selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO | ROUTE_TYPE_LIVE_VIDEO | ROUTE_TYPE_USER,
-                        sStatic.mDefaultAudioVideo);
+                selectDefaultRouteStatic();
             }
             if (!found) {
                 sStatic.mCategories.remove(removingCat);
@@ -752,7 +1070,7 @@
      *
      * @see #addUserRoute(UserRouteInfo)
      * @see #removeUserRoute(UserRouteInfo)
-     * @see #createRouteCategory(CharSequence)
+     * @see #createRouteCategory(CharSequence, boolean)
      */
     public UserRouteInfo createUserRoute(RouteCategory category) {
         return new UserRouteInfo(category);
@@ -780,6 +1098,23 @@
         return new RouteCategory(nameResId, ROUTE_TYPE_USER, isGroupable);
     }
 
+    /**
+     * Rebinds the media router to handle routes that belong to the specified user.
+     * Requires the interact across users permission to access the routes of another user.
+     * <p>
+     * This method is a complete hack to work around the singleton nature of the
+     * media router when running inside of singleton processes like QuickSettings.
+     * This mechanism should be burned to the ground when MediaRouter is redesigned.
+     * Ideally the current user would be pulled from the Context but we need to break
+     * down MediaRouter.Static before we can get there.
+     * </p>
+     *
+     * @hide
+     */
+    public void rebindAsUser(int userId) {
+        sStatic.rebindAsUser(userId);
+    }
+
     static void updateRoute(final RouteInfo info) {
         dispatchRouteChanged(info);
     }
@@ -906,7 +1241,7 @@
                     updateWifiDisplayRoute(route, d, newStatus);
                 }
                 if (d.equals(activeDisplay)) {
-                    selectRouteStatic(route.getSupportedTypes(), route);
+                    selectRouteStatic(route.getSupportedTypes(), route, false);
 
                     // Don't scan if we're already connected to a wifi display,
                     // the scanning process can cause a hiccup with some configurations.
@@ -919,7 +1254,7 @@
             if (d.isRemembered()) {
                 final WifiDisplay newDisplay = findMatchingDisplay(d, newDisplays);
                 if (newDisplay == null || !newDisplay.isRemembered()) {
-                    removeRoute(findWifiDisplayRoute(d));
+                    removeRouteStatic(findWifiDisplayRoute(d));
                 }
             }
         }
@@ -932,8 +1267,7 @@
     }
 
     static int getWifiDisplayStatusCode(WifiDisplay d, WifiDisplayStatus wfdStatus) {
-        int newStatus = RouteInfo.STATUS_NONE;
-
+        int newStatus;
         if (wfdStatus.getScanState() == WifiDisplayStatus.SCAN_STATE_SCANNING) {
             newStatus = RouteInfo.STATUS_SCANNING;
         } else if (d.isAvailable()) {
@@ -947,7 +1281,7 @@
             final int activeState = wfdStatus.getActiveDisplayState();
             switch (activeState) {
                 case WifiDisplayStatus.DISPLAY_STATE_CONNECTED:
-                    newStatus = RouteInfo.STATUS_NONE;
+                    newStatus = RouteInfo.STATUS_CONNECTED;
                     break;
                 case WifiDisplayStatus.DISPLAY_STATE_CONNECTING:
                     newStatus = RouteInfo.STATUS_CONNECTING;
@@ -968,7 +1302,8 @@
     static RouteInfo makeWifiDisplayRoute(WifiDisplay display, WifiDisplayStatus wfdStatus) {
         final RouteInfo newRoute = new RouteInfo(sStatic.mSystemCategory);
         newRoute.mDeviceAddress = display.getDeviceAddress();
-        newRoute.mSupportedTypes = ROUTE_TYPE_LIVE_AUDIO | ROUTE_TYPE_LIVE_VIDEO;
+        newRoute.mSupportedTypes = ROUTE_TYPE_LIVE_AUDIO | ROUTE_TYPE_LIVE_VIDEO
+                | ROUTE_TYPE_REMOTE_DISPLAY;
         newRoute.mVolumeHandling = RouteInfo.PLAYBACK_VOLUME_FIXED;
         newRoute.mPlaybackType = RouteInfo.PLAYBACK_TYPE_REMOTE;
 
@@ -1004,8 +1339,7 @@
 
         if (!enabled && route == sStatic.mSelectedRoute) {
             // Oops, no longer available. Reselect the default.
-            final RouteInfo defaultRoute = sStatic.mDefaultAudioVideo;
-            selectRouteStatic(defaultRoute.getSupportedTypes(), defaultRoute);
+            selectDefaultRouteStatic();
         }
     }
 
@@ -1075,6 +1409,10 @@
         String mDeviceAddress;
         boolean mEnabled = true;
 
+        // An id by which the route is known to the media router service.
+        // Null if this route only exists as an artifact within this process.
+        String mGlobalRouteId;
+
         // A predetermined connection status that can override mStatus
         private int mStatusCode;
 
@@ -1084,19 +1422,20 @@
         /** @hide */ public static final int STATUS_AVAILABLE = 3;
         /** @hide */ public static final int STATUS_NOT_AVAILABLE = 4;
         /** @hide */ public static final int STATUS_IN_USE = 5;
+        /** @hide */ public static final int STATUS_CONNECTED = 6;
 
         private Object mTag;
 
         /**
          * The default playback type, "local", indicating the presentation of the media is happening
          * on the same device (e.g. a phone, a tablet) as where it is controlled from.
-         * @see #setPlaybackType(int)
+         * @see #getPlaybackType()
          */
         public final static int PLAYBACK_TYPE_LOCAL = 0;
         /**
          * A playback type indicating the presentation of the media is happening on
          * a different device (i.e. the remote device) than where it is controlled from.
-         * @see #setPlaybackType(int)
+         * @see #getPlaybackType()
          */
         public final static int PLAYBACK_TYPE_REMOTE = 1;
         /**
@@ -1104,12 +1443,13 @@
          * controlled from this object. An example of fixed playback volume is a remote player,
          * playing over HDMI where the user prefers to control the volume on the HDMI sink, rather
          * than attenuate at the source.
-         * @see #setVolumeHandling(int)
+         * @see #getVolumeHandling()
          */
         public final static int PLAYBACK_VOLUME_FIXED = 0;
         /**
          * Playback information indicating the playback volume is variable and can be controlled
          * from this object.
+         * @see #getVolumeHandling()
          */
         public final static int PLAYBACK_VOLUME_VARIABLE = 1;
 
@@ -1181,7 +1521,7 @@
         boolean setStatusCode(int statusCode) {
             if (statusCode != mStatusCode) {
                 mStatusCode = statusCode;
-                int resId = 0;
+                int resId;
                 switch (statusCode) {
                     case STATUS_SCANNING:
                         resId = com.android.internal.R.string.media_route_status_scanning;
@@ -1198,6 +1538,11 @@
                     case STATUS_IN_USE:
                         resId = com.android.internal.R.string.media_route_status_in_use;
                         break;
+                    case STATUS_CONNECTED:
+                    case STATUS_NONE:
+                    default:
+                        resId = 0;
+                        break;
                 }
                 mStatus = resId != 0 ? sStatic.mResources.getText(resId) : null;
                 return true;
@@ -1317,9 +1662,7 @@
                     Log.e(TAG, "Error setting local stream volume", e);
                 }
             } else {
-                Log.e(TAG, getClass().getSimpleName() + ".requestSetVolume(): " +
-                        "Non-local volume playback on system route? " +
-                        "Could not request volume change.");
+                sStatic.requestSetVolume(this, volume);
             }
         }
 
@@ -1338,9 +1681,7 @@
                     Log.e(TAG, "Error setting local stream volume", e);
                 }
             } else {
-                Log.e(TAG, getClass().getSimpleName() + ".requestChangeVolume(): " +
-                        "Non-local volume playback on system route? " +
-                        "Could not request volume change.");
+                sStatic.requestUpdateVolume(this, direction);
             }
         }
 
@@ -1418,7 +1759,19 @@
          * @return True if this route is in the process of connecting.
          */
         public boolean isConnecting() {
-            return mStatusCode == STATUS_CONNECTING;
+            // If the route is selected and its status appears to be between states
+            // then report it as connecting even though it has not yet had a chance
+            // to move into the CONNECTING state.  Note that routes in the NONE state
+            // are assumed to not require an explicit connection lifecycle.
+            if (this == sStatic.mSelectedRoute) {
+                switch (mStatusCode) {
+                    case STATUS_AVAILABLE:
+                    case STATUS_SCANNING:
+                    case STATUS_CONNECTING:
+                        return true;
+                }
+            }
+            return false;
         }
 
         void setStatusInt(CharSequence status) {
@@ -1432,6 +1785,7 @@
         }
 
         final IRemoteVolumeObserver.Stub mRemoteVolObserver = new IRemoteVolumeObserver.Stub() {
+            @Override
             public void dispatchRemoteVolumeUpdate(final int direction, final int value) {
                 sStatic.mHandler.post(new Runnable() {
                     @Override
@@ -1460,7 +1814,7 @@
                     ", status=" + getStatus() +
                     ", category=" + getCategory() +
                     ", supportedTypes=" + supportedTypes +
-                    ", presentationDisplay=" + mPresentationDisplay + "}";
+                    ", presentationDisplay=" + mPresentationDisplay + " }";
         }
     }
 
@@ -1716,6 +2070,7 @@
             mVolumeHandling = PLAYBACK_VOLUME_FIXED;
         }
 
+        @Override
         CharSequence getName(Resources res) {
             if (mUpdateName) updateName();
             return super.getName(res);
@@ -1916,7 +2271,7 @@
             final int count = mRoutes.size();
             if (count == 0) {
                 // Don't keep empty groups in the router.
-                MediaRouter.removeRoute(this);
+                MediaRouter.removeRouteStatic(this);
                 return;
             }
 
@@ -2071,6 +2426,7 @@
             return mIsSystem;
         }
 
+        @Override
         public String toString() {
             return "RouteCategory{ name=" + mName + " types=" + typesToString(mTypes) +
                     " groupable=" + mGroupable + " }";
diff --git a/media/java/android/media/MediaRouterClientState.aidl b/media/java/android/media/MediaRouterClientState.aidl
new file mode 100644
index 0000000..70077119
--- /dev/null
+++ b/media/java/android/media/MediaRouterClientState.aidl
@@ -0,0 +1,18 @@
+/* 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 android.media;
+
+parcelable MediaRouterClientState;
diff --git a/media/java/android/media/MediaRouterClientState.java b/media/java/android/media/MediaRouterClientState.java
new file mode 100644
index 0000000..0847503
--- /dev/null
+++ b/media/java/android/media/MediaRouterClientState.java
@@ -0,0 +1,183 @@
+/*
+ * 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 android.media;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+
+/**
+ * Information available from MediaRouterService about the state perceived by
+ * a particular client and the routes that are available to it.
+ *
+ * Clients must not modify the contents of this object.
+ * @hide
+ */
+public final class MediaRouterClientState implements Parcelable {
+    /**
+     * A list of all known routes.
+     */
+    public final ArrayList<RouteInfo> routes;
+
+    /**
+     * The id of the current globally selected route, or null if none.
+     * Globally selected routes override any other route selections that applications
+     * may have made.  Used for remote displays.
+     */
+    public String globallySelectedRouteId;
+
+    public MediaRouterClientState() {
+        routes = new ArrayList<RouteInfo>();
+    }
+
+    MediaRouterClientState(Parcel src) {
+        routes = src.createTypedArrayList(RouteInfo.CREATOR);
+        globallySelectedRouteId = src.readString();
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeTypedList(routes);
+        dest.writeString(globallySelectedRouteId);
+    }
+
+    public static final Parcelable.Creator<MediaRouterClientState> CREATOR =
+            new Parcelable.Creator<MediaRouterClientState>() {
+        @Override
+        public MediaRouterClientState createFromParcel(Parcel in) {
+            return new MediaRouterClientState(in);
+        }
+
+        @Override
+        public MediaRouterClientState[] newArray(int size) {
+            return new MediaRouterClientState[size];
+        }
+    };
+
+    public static final class RouteInfo implements Parcelable {
+        public String id;
+        public String name;
+        public String description;
+        public int supportedTypes;
+        public boolean enabled;
+        public int statusCode;
+        public int playbackType;
+        public int playbackStream;
+        public int volume;
+        public int volumeMax;
+        public int volumeHandling;
+        public int presentationDisplayId;
+
+        public RouteInfo(String id) {
+            this.id = id;
+            enabled = true;
+            statusCode = MediaRouter.RouteInfo.STATUS_NONE;
+            playbackType = MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE;
+            playbackStream = -1;
+            volumeHandling = MediaRouter.RouteInfo.PLAYBACK_VOLUME_FIXED;
+            presentationDisplayId = -1;
+        }
+
+        public RouteInfo(RouteInfo other) {
+            id = other.id;
+            name = other.name;
+            description = other.description;
+            supportedTypes = other.supportedTypes;
+            enabled = other.enabled;
+            statusCode = other.statusCode;
+            playbackType = other.playbackType;
+            playbackStream = other.playbackStream;
+            volume = other.volume;
+            volumeMax = other.volumeMax;
+            volumeHandling = other.volumeHandling;
+            presentationDisplayId = other.presentationDisplayId;
+        }
+
+        RouteInfo(Parcel in) {
+            id = in.readString();
+            name = in.readString();
+            description = in.readString();
+            supportedTypes = in.readInt();
+            enabled = in.readInt() != 0;
+            statusCode = in.readInt();
+            playbackType = in.readInt();
+            playbackStream = in.readInt();
+            volume = in.readInt();
+            volumeMax = in.readInt();
+            volumeHandling = in.readInt();
+            presentationDisplayId = in.readInt();
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeString(id);
+            dest.writeString(name);
+            dest.writeString(description);
+            dest.writeInt(supportedTypes);
+            dest.writeInt(enabled ? 1 : 0);
+            dest.writeInt(statusCode);
+            dest.writeInt(playbackType);
+            dest.writeInt(playbackStream);
+            dest.writeInt(volume);
+            dest.writeInt(volumeMax);
+            dest.writeInt(volumeHandling);
+            dest.writeInt(presentationDisplayId);
+        }
+
+        @Override
+        public String toString() {
+            return "RouteInfo{ id=" + id
+                    + ", name=" + name
+                    + ", description=" + description
+                    + ", supportedTypes=0x" + Integer.toHexString(supportedTypes)
+                    + ", enabled=" + enabled
+                    + ", statusCode=" + statusCode
+                    + ", playbackType=" + playbackType
+                    + ", playbackStream=" + playbackStream
+                    + ", volume=" + volume
+                    + ", volumeMax=" + volumeMax
+                    + ", volumeHandling=" + volumeHandling
+                    + ", presentationDisplayId=" + presentationDisplayId
+                    + " }";
+        }
+
+        @SuppressWarnings("hiding")
+        public static final Parcelable.Creator<RouteInfo> CREATOR =
+                new Parcelable.Creator<RouteInfo>() {
+            @Override
+            public RouteInfo createFromParcel(Parcel in) {
+                return new RouteInfo(in);
+            }
+
+            @Override
+            public RouteInfo[] newArray(int size) {
+                return new RouteInfo[size];
+            }
+        };
+    }
+}
diff --git a/media/java/android/media/RemoteDisplayState.aidl b/media/java/android/media/RemoteDisplayState.aidl
new file mode 100644
index 0000000..b3262fc
--- /dev/null
+++ b/media/java/android/media/RemoteDisplayState.aidl
@@ -0,0 +1,18 @@
+/* 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 android.media;
+
+parcelable RemoteDisplayState;
diff --git a/media/java/android/media/RemoteDisplayState.java b/media/java/android/media/RemoteDisplayState.java
new file mode 100644
index 0000000..1197f65
--- /dev/null
+++ b/media/java/android/media/RemoteDisplayState.java
@@ -0,0 +1,189 @@
+/*
+ * 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 android.media;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+
+import java.util.ArrayList;
+
+/**
+ * Information available from IRemoteDisplayProvider about available remote displays.
+ *
+ * Clients must not modify the contents of this object.
+ * @hide
+ */
+public final class RemoteDisplayState implements Parcelable {
+    // Note: These constants are used by the remote display provider API.
+    // Do not change them!
+    public static final String SERVICE_INTERFACE =
+            "com.android.media.remotedisplay.RemoteDisplayProvider";
+    public static final int DISCOVERY_MODE_NONE = 0;
+    public static final int DISCOVERY_MODE_PASSIVE = 1;
+    public static final int DISCOVERY_MODE_ACTIVE = 2;
+
+    /**
+     * A list of all remote displays.
+     */
+    public final ArrayList<RemoteDisplayInfo> displays;
+
+    public RemoteDisplayState() {
+        displays = new ArrayList<RemoteDisplayInfo>();
+    }
+
+    RemoteDisplayState(Parcel src) {
+        displays = src.createTypedArrayList(RemoteDisplayInfo.CREATOR);
+    }
+
+    public boolean isValid() {
+        if (displays == null) {
+            return false;
+        }
+        final int count = displays.size();
+        for (int i = 0; i < count; i++) {
+            if (!displays.get(i).isValid()) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeTypedList(displays);
+    }
+
+    public static final Parcelable.Creator<RemoteDisplayState> CREATOR =
+            new Parcelable.Creator<RemoteDisplayState>() {
+        @Override
+        public RemoteDisplayState createFromParcel(Parcel in) {
+            return new RemoteDisplayState(in);
+        }
+
+        @Override
+        public RemoteDisplayState[] newArray(int size) {
+            return new RemoteDisplayState[size];
+        }
+    };
+
+    public static final class RemoteDisplayInfo implements Parcelable {
+        // Note: These constants are used by the remote display provider API.
+        // Do not change them!
+        public static final int STATUS_NOT_AVAILABLE = 0;
+        public static final int STATUS_IN_USE = 1;
+        public static final int STATUS_AVAILABLE = 2;
+        public static final int STATUS_CONNECTING = 3;
+        public static final int STATUS_CONNECTED = 4;
+
+        public static final int PLAYBACK_VOLUME_VARIABLE =
+                MediaRouter.RouteInfo.PLAYBACK_VOLUME_VARIABLE;
+        public static final int PLAYBACK_VOLUME_FIXED =
+                MediaRouter.RouteInfo.PLAYBACK_VOLUME_FIXED;
+
+        public String id;
+        public String name;
+        public String description;
+        public int status;
+        public int volume;
+        public int volumeMax;
+        public int volumeHandling;
+        public int presentationDisplayId;
+
+        public RemoteDisplayInfo(String id) {
+            this.id = id;
+            status = STATUS_NOT_AVAILABLE;
+            volumeHandling = MediaRouter.RouteInfo.PLAYBACK_VOLUME_FIXED;
+            presentationDisplayId = -1;
+        }
+
+        public RemoteDisplayInfo(RemoteDisplayInfo other) {
+            id = other.id;
+            name = other.name;
+            description = other.description;
+            status = other.status;
+            volume = other.volume;
+            volumeMax = other.volumeMax;
+            volumeHandling = other.volumeHandling;
+            presentationDisplayId = other.presentationDisplayId;
+        }
+
+        RemoteDisplayInfo(Parcel in) {
+            id = in.readString();
+            name = in.readString();
+            description = in.readString();
+            status = in.readInt();
+            volume = in.readInt();
+            volumeMax = in.readInt();
+            volumeHandling = in.readInt();
+            presentationDisplayId = in.readInt();
+        }
+
+        public boolean isValid() {
+            return !TextUtils.isEmpty(id) && !TextUtils.isEmpty(name);
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeString(id);
+            dest.writeString(name);
+            dest.writeString(description);
+            dest.writeInt(status);
+            dest.writeInt(volume);
+            dest.writeInt(volumeMax);
+            dest.writeInt(volumeHandling);
+            dest.writeInt(presentationDisplayId);
+        }
+
+        @Override
+        public String toString() {
+            return "RemoteDisplayInfo{ id=" + id
+                    + ", name=" + name
+                    + ", description=" + description
+                    + ", status=" + status
+                    + ", volume=" + volume
+                    + ", volumeMax=" + volumeMax
+                    + ", volumeHandling=" + volumeHandling
+                    + ", presentationDisplayId=" + presentationDisplayId
+                    + " }";
+        }
+
+        @SuppressWarnings("hiding")
+        public static final Parcelable.Creator<RemoteDisplayInfo> CREATOR =
+                new Parcelable.Creator<RemoteDisplayInfo>() {
+            @Override
+            public RemoteDisplayInfo createFromParcel(Parcel in) {
+                return new RemoteDisplayInfo(in);
+            }
+
+            @Override
+            public RemoteDisplayInfo[] newArray(int size) {
+                return new RemoteDisplayInfo[size];
+            }
+        };
+    }
+}
diff --git a/media/lib/Android.mk b/media/lib/Android.mk
new file mode 100644
index 0000000..50799a6
--- /dev/null
+++ b/media/lib/Android.mk
@@ -0,0 +1,46 @@
+#
+# 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.
+#
+LOCAL_PATH := $(call my-dir)
+
+# the library
+# ============================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE:= com.android.media.remotedisplay
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := \
+            $(call all-subdir-java-files) \
+            $(call all-aidl-files-under, java)
+
+include $(BUILD_JAVA_LIBRARY)
+
+
+# ====  com.android.media.remotedisplay.xml lib def  ========================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := com.android.media.remotedisplay.xml
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE_CLASS := ETC
+
+# This will install the file in /system/etc/permissions
+#
+LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/permissions
+
+LOCAL_SRC_FILES := $(LOCAL_MODULE)
+
+include $(BUILD_PREBUILT)
diff --git a/media/lib/README.txt b/media/lib/README.txt
new file mode 100644
index 0000000..cade3df
--- /dev/null
+++ b/media/lib/README.txt
@@ -0,0 +1,28 @@
+This library (com.android.media.remotedisplay.jar) is a shared java library
+containing classes required by unbundled remote display providers.
+
+--- Rules of this library ---
+o This library is effectively a PUBLIC API for unbundled remote display providers
+  that may be distributed outside the system image. So it MUST BE API STABLE.
+  You can add but not remove. The rules are the same as for the
+  public platform SDK API.
+o This library can see and instantiate internal platform classes, but it must not
+  expose them in any public method (or by extending them via inheritance). This would
+  break clients of the library because they cannot see the internal platform classes.
+
+This library is distributed in the system image, and loaded as
+a shared library. So you can change the implementation, but not
+the interface. In this way it is like framework.jar.
+
+--- Why does this library exists? ---
+
+Unbundled remote display providers (such as Cast) cannot use internal
+platform classes.
+
+This library will eventually be replaced when the media route provider
+infrastructure that is currently defined in the support library is reintegrated
+with the framework in a new API.  That API isn't ready yet so this
+library is a compromise to make new capabilities available to the system
+without exposing the full surface area of the support library media
+route provider protocol.
+
diff --git a/media/lib/com.android.media.remotedisplay.xml b/media/lib/com.android.media.remotedisplay.xml
new file mode 100644
index 0000000..77a91d2
--- /dev/null
+++ b/media/lib/com.android.media.remotedisplay.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<permissions>
+    <library name="com.android.media.remotedisplay"
+            file="/system/framework/com.android.media.remotedisplay.jar" />
+</permissions>
diff --git a/media/lib/java/com/android/media/remotedisplay/RemoteDisplay.java b/media/lib/java/com/android/media/remotedisplay/RemoteDisplay.java
new file mode 100644
index 0000000..5e15702
--- /dev/null
+++ b/media/lib/java/com/android/media/remotedisplay/RemoteDisplay.java
@@ -0,0 +1,173 @@
+/*
+ * 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.android.media.remotedisplay;
+
+import com.android.internal.util.Objects;
+
+import android.media.MediaRouter;
+import android.media.RemoteDisplayState.RemoteDisplayInfo;
+import android.text.TextUtils;
+
+/**
+ * Represents a remote display that has been discovered.
+ */
+public class RemoteDisplay {
+    private final RemoteDisplayInfo mMutableInfo;
+    private RemoteDisplayInfo mImmutableInfo;
+
+    /**
+     * Status code: Indicates that the remote display is not available.
+     */
+    public static final int STATUS_NOT_AVAILABLE = RemoteDisplayInfo.STATUS_NOT_AVAILABLE;
+
+    /**
+     * Status code: Indicates that the remote display is in use by someone else.
+     */
+    public static final int STATUS_IN_USE = RemoteDisplayInfo.STATUS_IN_USE;
+
+    /**
+     * Status code: Indicates that the remote display is available for new connections.
+     */
+    public static final int STATUS_AVAILABLE = RemoteDisplayInfo.STATUS_AVAILABLE;
+
+    /**
+     * Status code: Indicates that the remote display is current connecting.
+     */
+    public static final int STATUS_CONNECTING = RemoteDisplayInfo.STATUS_CONNECTING;
+
+    /**
+     * Status code: Indicates that the remote display is connected and is mirroring
+     * display contents.
+     */
+    public static final int STATUS_CONNECTED = RemoteDisplayInfo.STATUS_CONNECTED;
+
+    /**
+     * Volume handling: Output volume can be changed.
+     */
+    public static final int PLAYBACK_VOLUME_VARIABLE =
+            RemoteDisplayInfo.PLAYBACK_VOLUME_VARIABLE;
+
+    /**
+     * Volume handling: Output volume is fixed.
+     */
+    public static final int PLAYBACK_VOLUME_FIXED =
+            RemoteDisplayInfo.PLAYBACK_VOLUME_FIXED;
+
+    /**
+     * Creates a remote display with the specified name and id.
+     */
+    public RemoteDisplay(String id, String name) {
+        if (TextUtils.isEmpty(id)) {
+            throw new IllegalArgumentException("id must not be null or empty");
+        }
+        mMutableInfo = new RemoteDisplayInfo(id);
+        setName(name);
+    }
+
+    public String getId() {
+        return mMutableInfo.id;
+    }
+
+    public String getName() {
+        return mMutableInfo.name;
+    }
+
+    public void setName(String name) {
+        if (!Objects.equal(mMutableInfo.name, name)) {
+            mMutableInfo.name = name;
+            mImmutableInfo = null;
+        }
+    }
+
+    public String getDescription() {
+        return mMutableInfo.description;
+    }
+
+    public void setDescription(String description) {
+        if (!Objects.equal(mMutableInfo.description, description)) {
+            mMutableInfo.description = description;
+            mImmutableInfo = null;
+        }
+    }
+
+    public int getStatus() {
+        return mMutableInfo.status;
+    }
+
+    public void setStatus(int status) {
+        if (mMutableInfo.status != status) {
+            mMutableInfo.status = status;
+            mImmutableInfo = null;
+        }
+    }
+
+    public int getVolume() {
+        return mMutableInfo.volume;
+    }
+
+    public void setVolume(int volume) {
+        if (mMutableInfo.volume != volume) {
+            mMutableInfo.volume = volume;
+            mImmutableInfo = null;
+        }
+    }
+
+    public int getVolumeMax() {
+        return mMutableInfo.volumeMax;
+    }
+
+    public void setVolumeMax(int volumeMax) {
+        if (mMutableInfo.volumeMax != volumeMax) {
+            mMutableInfo.volumeMax = volumeMax;
+            mImmutableInfo = null;
+        }
+    }
+
+    public int getVolumeHandling() {
+        return mMutableInfo.volumeHandling;
+    }
+
+    public void setVolumeHandling(int volumeHandling) {
+        if (mMutableInfo.volumeHandling != volumeHandling) {
+            mMutableInfo.volumeHandling = volumeHandling;
+            mImmutableInfo = null;
+        }
+    }
+
+    public int getPresentationDisplayId() {
+        return mMutableInfo.presentationDisplayId;
+    }
+
+    public void setPresentationDisplayId(int presentationDisplayId) {
+        if (mMutableInfo.presentationDisplayId != presentationDisplayId) {
+            mMutableInfo.presentationDisplayId = presentationDisplayId;
+            mImmutableInfo = null;
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "RemoteDisplay{" + mMutableInfo.toString() + "}";
+    }
+
+    RemoteDisplayInfo getInfo() {
+        if (mImmutableInfo == null) {
+            mImmutableInfo = new RemoteDisplayInfo(mMutableInfo);
+        }
+        return mImmutableInfo;
+    }
+}
diff --git a/media/lib/java/com/android/media/remotedisplay/RemoteDisplayProvider.java b/media/lib/java/com/android/media/remotedisplay/RemoteDisplayProvider.java
new file mode 100644
index 0000000..8e4042c
--- /dev/null
+++ b/media/lib/java/com/android/media/remotedisplay/RemoteDisplayProvider.java
@@ -0,0 +1,371 @@
+/*
+ * 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.android.media.remotedisplay;
+
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.media.IRemoteDisplayCallback;
+import android.media.IRemoteDisplayProvider;
+import android.media.RemoteDisplayState;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.util.ArrayMap;
+
+import java.util.Collection;
+
+/**
+ * Base class for remote display providers implemented as unbundled services.
+ * <p>
+ * To implement your remote display provider service, create a subclass of
+ * {@link Service} and override the {@link Service#onBind Service.onBind()} method
+ * to return the provider's binder when the {@link #SERVICE_INTERFACE} is requested.
+ * </p>
+ * <pre>
+ *   public class SampleRemoteDisplayProviderService extends Service {
+ *       private SampleProvider mProvider;
+ *
+ *       public IBinder onBind(Intent intent) {
+ *           if (intent.getAction().equals(RemoteDisplayProvider.SERVICE_INTERFACE)) {
+ *               if (mProvider == null) {
+ *                   mProvider = new SampleProvider(this);
+ *               }
+ *               return mProvider.getBinder();
+ *           }
+ *           return null;
+ *       }
+ *
+ *       class SampleProvider extends RemoteDisplayProvider {
+ *           public SampleProvider() {
+ *               super(SampleRemoteDisplayProviderService.this);
+ *           }
+ *
+ *           // --- Implementation goes here ---
+ *       }
+ *   }
+ * </pre>
+ * <p>
+ * Declare your remote display provider service in your application manifest
+ * like this:
+ * </p>
+ * <pre>
+ *   &lt;application>
+ *       &lt;uses-library android:name="com.android.media.remotedisplay" />
+ *
+ *       &lt;service android:name=".SampleRemoteDisplayProviderService"
+ *               android:label="@string/sample_remote_display_provider_service"
+ *               android:exported="true"
+ *               android:permission="android.permission.BIND_REMOTE_DISPLAY">
+ *           &lt;intent-filter>
+ *               &lt;action android:name="com.android.media.remotedisplay.RemoteDisplayProvider" />
+ *           &lt;/intent-filter>
+ *       &lt;/service>
+ *   &lt;/application>
+ * </pre>
+ * <p>
+ * This object is not thread safe.  It is only intended to be accessed on the
+ * {@link Context#getMainLooper main looper thread} of an application.
+ * </p><p>
+ * IMPORTANT: This class is effectively a public API for unbundled applications, and
+ * must remain API stable. See README.txt in the root of this package for more information.
+ * </p>
+ */
+public abstract class RemoteDisplayProvider {
+    private static final int MSG_SET_CALLBACK = 1;
+    private static final int MSG_SET_DISCOVERY_MODE = 2;
+    private static final int MSG_CONNECT = 3;
+    private static final int MSG_DISCONNECT = 4;
+    private static final int MSG_SET_VOLUME = 5;
+    private static final int MSG_ADJUST_VOLUME = 6;
+
+    private final ProviderStub mStub;
+    private final ProviderHandler mHandler;
+    private final ArrayMap<String, RemoteDisplay> mDisplays =
+            new ArrayMap<String, RemoteDisplay>();
+    private IRemoteDisplayCallback mCallback;
+    private int mDiscoveryMode = DISCOVERY_MODE_NONE;
+
+    /**
+     * The {@link Intent} that must be declared as handled by the service.
+     * Put this in your manifest.
+     */
+    public static final String SERVICE_INTERFACE = RemoteDisplayState.SERVICE_INTERFACE;
+
+    /**
+     * Discovery mode: Do not perform any discovery.
+     */
+    public static final int DISCOVERY_MODE_NONE = RemoteDisplayState.DISCOVERY_MODE_NONE;
+
+    /**
+     * Discovery mode: Passive or low-power periodic discovery.
+     * <p>
+     * This mode indicates that an application is interested in knowing whether there
+     * are any remote displays paired or available but doesn't need the latest or
+     * most detailed information.  The provider may scan at a lower rate or rely on
+     * knowledge of previously paired devices.
+     * </p>
+     */
+    public static final int DISCOVERY_MODE_PASSIVE = RemoteDisplayState.DISCOVERY_MODE_PASSIVE;
+
+    /**
+     * Discovery mode: Active discovery.
+     * <p>
+     * This mode indicates that the user is actively trying to connect to a route
+     * and we should perform continuous scans.  This mode may use significantly more
+     * power but is intended to be short-lived.
+     * </p>
+     */
+    public static final int DISCOVERY_MODE_ACTIVE = RemoteDisplayState.DISCOVERY_MODE_ACTIVE;
+
+    /**
+     * Creates a remote display provider.
+     *
+     * @param context The application context for the remote display provider.
+     */
+    public RemoteDisplayProvider(Context context) {
+        mStub = new ProviderStub();
+        mHandler = new ProviderHandler(context.getMainLooper());
+    }
+
+    /**
+     * Gets the Binder associated with the provider.
+     * <p>
+     * This is intended to be used for the onBind() method of a service that implements
+     * a remote display provider service.
+     * </p>
+     *
+     * @return The IBinder instance associated with the provider.
+     */
+    public IBinder getBinder() {
+        return mStub;
+    }
+
+    /**
+     * Called when the current discovery mode changes.
+     *
+     * @param mode The new discovery mode.
+     */
+    public void onDiscoveryModeChanged(int mode) {
+    }
+
+    /**
+     * Called when the system would like to connect to a display.
+     *
+     * @param display The remote display.
+     */
+    public void onConnect(RemoteDisplay display) {
+    }
+
+    /**
+     * Called when the system would like to disconnect from a display.
+     *
+     * @param display The remote display.
+     */
+    public void onDisconnect(RemoteDisplay display) {
+    }
+
+    /**
+     * Called when the system would like to set the volume of a display.
+     *
+     * @param display The remote display.
+     * @param volume The desired volume.
+     */
+    public void onSetVolume(RemoteDisplay display, int volume) {
+    }
+
+    /**
+     * Called when the system would like to adjust the volume of a display.
+     *
+     * @param display The remote display.
+     * @param delta An increment to add to the current volume, such as +1 or -1.
+     */
+    public void onAdjustVolume(RemoteDisplay display, int delta) {
+    }
+
+    /**
+     * Gets the current discovery mode.
+     *
+     * @return The current discovery mode.
+     */
+    public int getDiscoveryMode() {
+        return mDiscoveryMode;
+    }
+
+    /**
+     * Gets the current collection of displays.
+     *
+     * @return The current collection of displays, which must not be modified.
+     */
+    public Collection<RemoteDisplay> getDisplays() {
+        return mDisplays.values();
+    }
+
+    /**
+     * Adds the specified remote display and notifies the system.
+     *
+     * @param display The remote display that was added.
+     * @throws IllegalStateException if there is already a display with the same id.
+     */
+    public void addDisplay(RemoteDisplay display) {
+        if (display == null || mDisplays.containsKey(display.getId())) {
+            throw new IllegalArgumentException("display");
+        }
+        mDisplays.put(display.getId(), display);
+        publishState();
+    }
+
+    /**
+     * Updates information about the specified remote display and notifies the system.
+     *
+     * @param display The remote display that was added.
+     * @throws IllegalStateException if the display was n
+     */
+    public void updateDisplay(RemoteDisplay display) {
+        if (display == null || mDisplays.get(display.getId()) != display) {
+            throw new IllegalArgumentException("display");
+        }
+        publishState();
+    }
+
+    /**
+     * Removes the specified remote display and tells the system about it.
+     *
+     * @param display The remote display that was removed.
+     */
+    public void removeDisplay(RemoteDisplay display) {
+        if (display == null || mDisplays.get(display.getId()) != display) {
+            throw new IllegalArgumentException("display");
+        }
+        mDisplays.remove(display.getId());
+        publishState();
+    }
+
+    void setCallback(IRemoteDisplayCallback callback) {
+        mCallback = callback;
+        publishState();
+    }
+
+    void setDiscoveryMode(int mode) {
+        if (mDiscoveryMode != mode) {
+            mDiscoveryMode = mode;
+            onDiscoveryModeChanged(mode);
+        }
+    }
+
+    void publishState() {
+        if (mCallback != null) {
+            RemoteDisplayState state = new RemoteDisplayState();
+            final int count = mDisplays.size();
+            for (int i = 0; i < count; i++) {
+                final RemoteDisplay display = mDisplays.valueAt(i);
+                state.displays.add(display.getInfo());
+            }
+            try {
+                mCallback.onStateChanged(state);
+            } catch (RemoteException ex) {
+                // system server died?
+            }
+        }
+    }
+
+    RemoteDisplay findRemoteDisplay(String id) {
+        return mDisplays.get(id);
+    }
+
+    final class ProviderStub extends IRemoteDisplayProvider.Stub {
+        @Override
+        public void setCallback(IRemoteDisplayCallback callback) {
+            mHandler.obtainMessage(MSG_SET_CALLBACK, callback).sendToTarget();
+        }
+
+        @Override
+        public void setDiscoveryMode(int mode) {
+            mHandler.obtainMessage(MSG_SET_DISCOVERY_MODE, mode, 0).sendToTarget();
+        }
+
+        @Override
+        public void connect(String id) {
+            mHandler.obtainMessage(MSG_CONNECT, id).sendToTarget();
+        }
+
+        @Override
+        public void disconnect(String id) {
+            mHandler.obtainMessage(MSG_DISCONNECT, id).sendToTarget();
+        }
+
+        @Override
+        public void setVolume(String id, int volume) {
+            mHandler.obtainMessage(MSG_SET_VOLUME, volume, 0, id).sendToTarget();
+        }
+
+        @Override
+        public void adjustVolume(String id, int delta) {
+            mHandler.obtainMessage(MSG_ADJUST_VOLUME, delta, 0, id).sendToTarget();
+        }
+    }
+
+    final class ProviderHandler extends Handler {
+        public ProviderHandler(Looper looper) {
+            super(looper, null, true);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_SET_CALLBACK: {
+                    setCallback((IRemoteDisplayCallback)msg.obj);
+                    break;
+                }
+                case MSG_SET_DISCOVERY_MODE: {
+                    setDiscoveryMode(msg.arg1);
+                    break;
+                }
+                case MSG_CONNECT: {
+                    RemoteDisplay display = findRemoteDisplay((String)msg.obj);
+                    if (display != null) {
+                        onConnect(display);
+                    }
+                    break;
+                }
+                case MSG_DISCONNECT: {
+                    RemoteDisplay display = findRemoteDisplay((String)msg.obj);
+                    if (display != null) {
+                        onDisconnect(display);
+                    }
+                    break;
+                }
+                case MSG_SET_VOLUME: {
+                    RemoteDisplay display = findRemoteDisplay((String)msg.obj);
+                    if (display != null) {
+                        onSetVolume(display, msg.arg1);
+                    }
+                    break;
+                }
+                case MSG_ADJUST_VOLUME: {
+                    RemoteDisplay display = findRemoteDisplay((String)msg.obj);
+                    if (display != null) {
+                        onAdjustVolume(display, msg.arg1);
+                    }
+                    break;
+                }
+            }
+        }
+    }
+}
diff --git a/packages/FusedLocation/res/values-ca/strings.xml b/packages/FusedLocation/res/values-ca/strings.xml
index bdd55dd..9dae512 100644
--- a/packages/FusedLocation/res/values-ca/strings.xml
+++ b/packages/FusedLocation/res/values-ca/strings.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="5379477904423203699">"Ubicació unificada"</string>
+    <string name="app_label" msgid="5379477904423203699">"Ubicació combinada"</string>
 </resources>
diff --git a/packages/FusedLocation/res/values-de/strings.xml b/packages/FusedLocation/res/values-de/strings.xml
index 0d2cccc..d7e5faa 100644
--- a/packages/FusedLocation/res/values-de/strings.xml
+++ b/packages/FusedLocation/res/values-de/strings.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="5379477904423203699">"Fused Location"</string>
+    <string name="app_label" msgid="5379477904423203699">"Kombinierte Standortbestimmung"</string>
 </resources>
diff --git a/packages/FusedLocation/res/values-pt/strings.xml b/packages/FusedLocation/res/values-pt/strings.xml
index cf5f5bf..4f8277a 100644
--- a/packages/FusedLocation/res/values-pt/strings.xml
+++ b/packages/FusedLocation/res/values-pt/strings.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="5379477904423203699">"Localização fundida"</string>
+    <string name="app_label" msgid="5379477904423203699">"Localização combinada"</string>
 </resources>
diff --git a/packages/Keyguard/res/layout/keyguard_presentation.xml b/packages/Keyguard/res/layout/keyguard_presentation.xml
new file mode 100644
index 0000000..7df0b70
--- /dev/null
+++ b/packages/Keyguard/res/layout/keyguard_presentation.xml
@@ -0,0 +1,63 @@
+<?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.
+*/
+-->
+
+<!-- This is a view that shows general status information in Keyguard. -->
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/res/com.android.keyguard"
+    android:id="@+id/presentation"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <com.android.keyguard.KeyguardStatusView
+        android:id="@+id/clock"
+        android:orientation="vertical"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:contentDescription="@string/keyguard_accessibility_status">
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_horizontal|top"
+            android:orientation="vertical"
+            android:focusable="true">
+            <TextClock
+                android:id="@+id/clock_view"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center_horizontal|top"
+                android:textColor="@color/clock_white"
+                android:singleLine="true"
+                style="@style/widget_big_thin"
+                android:format12Hour="@string/keyguard_widget_12_hours_format"
+                android:format24Hour="@string/keyguard_widget_24_hours_format"
+                android:baselineAligned="true"
+                android:layout_marginBottom="@dimen/bottom_text_spacing_digital" />
+
+            <include layout="@layout/keyguard_status_area" />
+            <ImageView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="10dip"
+                android:layout_gravity="center_horizontal"
+                android:src="@drawable/kg_security_lock_normal" />
+        </LinearLayout>
+    </com.android.keyguard.KeyguardStatusView>
+
+</FrameLayout>
diff --git a/packages/Keyguard/res/layout/keyguard_status_view.xml b/packages/Keyguard/res/layout/keyguard_status_view.xml
index 5857fc2..a4d298a 100644
--- a/packages/Keyguard/res/layout/keyguard_status_view.xml
+++ b/packages/Keyguard/res/layout/keyguard_status_view.xml
@@ -26,7 +26,7 @@
     android:layout_height="match_parent"
     androidprv:layout_maxWidth="@dimen/keyguard_security_width"
     androidprv:layout_maxHeight="@dimen/keyguard_security_height"
-    android:gravity="center_horizontal">
+    android:gravity="center">
 
     <com.android.keyguard.KeyguardStatusView
         android:id="@+id/keyguard_status_view_face_palm"
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardDisplayManager.java b/packages/Keyguard/src/com/android/keyguard/KeyguardDisplayManager.java
new file mode 100644
index 0000000..6bcbd6c
--- /dev/null
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardDisplayManager.java
@@ -0,0 +1,171 @@
+/*
+ * 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.android.keyguard;
+
+import android.app.Presentation;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnDismissListener;
+import android.graphics.Point;
+import android.media.MediaRouter;
+import android.media.MediaRouter.RouteInfo;
+import android.os.Bundle;
+import android.util.Slog;
+import android.view.Display;
+import android.view.View;
+import android.view.WindowManager;
+
+public class KeyguardDisplayManager {
+    protected static final String TAG = "KeyguardDisplayManager";
+    private static boolean DEBUG = KeyguardViewMediator.DEBUG;
+    Presentation mPresentation;
+    private MediaRouter mMediaRouter;
+    private Context mContext;
+    private boolean mShowing;
+
+    KeyguardDisplayManager(Context context) {
+        mContext = context;
+        mMediaRouter = (MediaRouter) mContext.getSystemService(Context.MEDIA_ROUTER_SERVICE);
+    }
+
+    void show() {
+        if (!mShowing) {
+            if (DEBUG) Slog.v(TAG, "show");
+            mMediaRouter.addCallback(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY,
+                    mMediaRouterCallback, MediaRouter.CALLBACK_FLAG_PASSIVE_DISCOVERY);
+            updateDisplays(true);
+        }
+        mShowing = true;
+    }
+
+    void hide() {
+        if (mShowing) {
+            if (DEBUG) Slog.v(TAG, "hide");
+            mMediaRouter.removeCallback(mMediaRouterCallback);
+            updateDisplays(false);
+        }
+        mShowing = false;
+    }
+
+    private final MediaRouter.SimpleCallback mMediaRouterCallback =
+            new MediaRouter.SimpleCallback() {
+        @Override
+        public void onRouteSelected(MediaRouter router, int type, RouteInfo info) {
+            if (DEBUG) Slog.d(TAG, "onRouteSelected: type=" + type + ", info=" + info);
+            updateDisplays(mShowing);
+        }
+
+        @Override
+        public void onRouteUnselected(MediaRouter router, int type, RouteInfo info) {
+            if (DEBUG) Slog.d(TAG, "onRouteUnselected: type=" + type + ", info=" + info);
+            updateDisplays(mShowing);
+        }
+
+        @Override
+        public void onRoutePresentationDisplayChanged(MediaRouter router, RouteInfo info) {
+            if (DEBUG) Slog.d(TAG, "onRoutePresentationDisplayChanged: info=" + info);
+            updateDisplays(mShowing);
+        }
+    };
+
+    private OnDismissListener mOnDismissListener = new OnDismissListener() {
+
+        @Override
+        public void onDismiss(DialogInterface dialog) {
+            mPresentation = null;
+        }
+    };
+
+    protected void updateDisplays(boolean showing) {
+        if (showing) {
+            MediaRouter.RouteInfo route = mMediaRouter.getSelectedRoute(
+                    MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY);
+            boolean useDisplay = route != null
+                    && route.getPlaybackType() == MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE;
+            Display presentationDisplay = useDisplay ? route.getPresentationDisplay() : null;
+
+            if (mPresentation != null && mPresentation.getDisplay() != presentationDisplay) {
+                if (DEBUG) Slog.v(TAG, "Display gone: " + mPresentation.getDisplay());
+                mPresentation.dismiss();
+                mPresentation = null;
+            }
+
+            if (mPresentation == null && presentationDisplay != null) {
+                if (DEBUG) Slog.i(TAG, "Keyguard enabled on display: " + presentationDisplay);
+                mPresentation = new KeyguardPresentation(mContext, presentationDisplay);
+                mPresentation.setOnDismissListener(mOnDismissListener);
+                try {
+                    mPresentation.show();
+                } catch (WindowManager.InvalidDisplayException ex) {
+                    Slog.w(TAG, "Invalid display:", ex);
+                    mPresentation = null;
+                }
+            }
+        } else {
+            if (mPresentation != null) {
+                mPresentation.dismiss();
+                mPresentation = null;
+            }
+        }
+    }
+
+    private final static class KeyguardPresentation extends Presentation {
+        private static final int VIDEO_SAFE_REGION = 80; // Percentage of display width & height
+        private static final int MOVE_CLOCK_TIMEOUT = 10000; // 10s
+        private View mClock;
+        private int mUsableWidth;
+        private int mUsableHeight;
+        private int mMarginTop;
+        private int mMarginLeft;
+        Runnable mMoveTextRunnable = new Runnable() {
+            @Override
+            public void run() {
+                int x = mMarginLeft + (int) (Math.random() * (mUsableWidth - mClock.getWidth()));
+                int y = mMarginTop + (int) (Math.random() * (mUsableHeight - mClock.getHeight()));
+                mClock.setTranslationX(x);
+                mClock.setTranslationY(y);
+                mClock.postDelayed(mMoveTextRunnable, MOVE_CLOCK_TIMEOUT);
+            }
+        };
+
+        public KeyguardPresentation(Context context, Display display) {
+            super(context, display);
+            getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
+        }
+
+        public void onDetachedFromWindow() {
+            mClock.removeCallbacks(mMoveTextRunnable);
+        }
+
+        @Override
+        protected void onCreate(Bundle savedInstanceState) {
+            super.onCreate(savedInstanceState);
+
+            Point p = new Point();
+            getDisplay().getSize(p);
+            mUsableWidth = VIDEO_SAFE_REGION * p.x/100;
+            mUsableHeight = VIDEO_SAFE_REGION * p.y/100;
+            mMarginLeft = (100 - VIDEO_SAFE_REGION) * p.x / 200;
+            mMarginTop = (100 - VIDEO_SAFE_REGION) * p.y / 200;
+
+            setContentView(R.layout.keyguard_presentation);
+            mClock = findViewById(R.id.clock);
+
+            // Avoid screen burn in
+            mClock.post(mMoveTextRunnable);
+        }
+    }
+}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardTransportControlView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardTransportControlView.java
index 2719c5c..349078f 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardTransportControlView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardTransportControlView.java
@@ -60,12 +60,12 @@
  */
 public class KeyguardTransportControlView extends FrameLayout {
 
-    private static final int DISPLAY_TIMEOUT_MS = 5000; // 5s
     private static final int RESET_TO_METADATA_DELAY = 5000;
     protected static final boolean DEBUG = false;
     protected static final String TAG = "TransportControlView";
 
     private static final boolean ANIMATE_TRANSITIONS = true;
+    protected static final long QUIESCENT_PLAYBACK_FACTOR = 1000;
 
     private ViewGroup mMetadataContainer;
     private ViewGroup mInfoContainer;
@@ -89,11 +89,9 @@
     private ImageView mBadge;
 
     private boolean mSeekEnabled;
-    private boolean mUserSeeking;
     private java.text.DateFormat mFormat;
 
-    private Date mTimeElapsed;
-    private Date mTrackDuration;
+    private Date mTempDate = new Date();
 
     /**
      * The metadata which should be populated into the view once we've been attached
@@ -111,18 +109,25 @@
 
         @Override
         public void onClientPlaybackStateUpdate(int state) {
-            setSeekBarsEnabled(false);
             updatePlayPauseState(state);
         }
 
         @Override
         public void onClientPlaybackStateUpdate(int state, long stateChangeTimeMs,
                 long currentPosMs, float speed) {
-            setSeekBarsEnabled(mMetadata != null && mMetadata.duration > 0);
             updatePlayPauseState(state);
             if (DEBUG) Log.d(TAG, "onClientPlaybackStateUpdate(state=" + state +
                     ", stateChangeTimeMs=" + stateChangeTimeMs + ", currentPosMs=" + currentPosMs +
                     ", speed=" + speed + ")");
+
+            removeCallbacks(mUpdateSeekBars);
+            // Since the music client may be responding to historical events that cause the
+            // playback state to change dramatically, wait until things become quiescent before
+            // resuming automatic scrub position update.
+            if (mTransientSeek.getVisibility() == View.VISIBLE
+                    && playbackPositionShouldMove(mCurrentPlayState)) {
+                postDelayed(mUpdateSeekBars, QUIESCENT_PLAYBACK_FACTOR);
+            }
         }
 
         @Override
@@ -136,15 +141,21 @@
         }
     };
 
-    private final Runnable mUpdateSeekBars = new Runnable() {
+    private class UpdateSeekBarRunnable implements  Runnable {
         public void run() {
-            if (updateSeekBars()) {
+            boolean seekAble = updateOnce();
+            if (seekAble) {
                 removeCallbacks(this);
                 postDelayed(this, 1000);
             }
         }
+        public boolean updateOnce() {
+            return updateSeekBars();
+        }
     };
 
+    private final UpdateSeekBarRunnable mUpdateSeekBars = new UpdateSeekBarRunnable();
+
     private final Runnable mResetToMetadata = new Runnable() {
         public void run() {
             resetToMetadata();
@@ -163,6 +174,7 @@
             }
             if (keyCode != -1) {
                 sendMediaButtonClick(keyCode);
+                delayResetToMetadata(); // if the scrub bar is showing, keep showing it.
             }
         }
     };
@@ -177,25 +189,67 @@
         }
     };
 
+    // This class is here to throttle scrub position updates to the music client
+    class FutureSeekRunnable implements Runnable {
+        private int mProgress;
+        private boolean mPending;
+
+        public void run() {
+            scrubTo(mProgress);
+            mPending = false;
+        }
+
+        void setProgress(int progress) {
+            mProgress = progress;
+            if (!mPending) {
+                mPending = true;
+                postDelayed(this, 30);
+            }
+        }
+    };
+
+    // This is here because RemoteControlClient's method isn't visible :/
+    private final static boolean playbackPositionShouldMove(int playstate) {
+        switch(playstate) {
+            case RemoteControlClient.PLAYSTATE_STOPPED:
+            case RemoteControlClient.PLAYSTATE_PAUSED:
+            case RemoteControlClient.PLAYSTATE_BUFFERING:
+            case RemoteControlClient.PLAYSTATE_ERROR:
+            case RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS:
+            case RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS:
+                return false;
+            case RemoteControlClient.PLAYSTATE_PLAYING:
+            case RemoteControlClient.PLAYSTATE_FAST_FORWARDING:
+            case RemoteControlClient.PLAYSTATE_REWINDING:
+            default:
+                return true;
+        }
+    }
+
+    private final FutureSeekRunnable mFutureSeekRunnable = new FutureSeekRunnable();
+
     private final SeekBar.OnSeekBarChangeListener mOnSeekBarChangeListener =
             new SeekBar.OnSeekBarChangeListener() {
         @Override
         public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
             if (fromUser) {
-                scrubTo(progress);
+                mFutureSeekRunnable.setProgress(progress);
                 delayResetToMetadata();
+                mTempDate.setTime(progress);
+                mTransientSeekTimeElapsed.setText(mFormat.format(mTempDate));
+            } else {
+                updateSeekDisplay();
             }
-            updateSeekDisplay();
         }
 
         @Override
         public void onStartTrackingTouch(SeekBar seekBar) {
-            mUserSeeking = true;
+            delayResetToMetadata();
+            removeCallbacks(mUpdateSeekBars); // don't update during user interaction
         }
 
         @Override
         public void onStopTrackingTouch(SeekBar seekBar) {
-            mUserSeeking = false;
         }
     };
 
@@ -247,17 +301,11 @@
         if (enabled == mSeekEnabled) return;
 
         mSeekEnabled = enabled;
-        if (mTransientSeek.getVisibility() == VISIBLE) {
+        if (mTransientSeek.getVisibility() == VISIBLE && !enabled) {
             mTransientSeek.setVisibility(INVISIBLE);
             mMetadataContainer.setVisibility(VISIBLE);
-            mUserSeeking = false;
             cancelResetToMetadata();
         }
-        if (enabled) {
-            mUpdateSeekBars.run();
-        } else {
-            removeCallbacks(mUpdateSeekBars);
-        }
     }
 
     public void setTransportControlCallback(KeyguardHostView.TransportControlCallback
@@ -294,6 +342,8 @@
         }
         final boolean screenOn = KeyguardUpdateMonitor.getInstance(mContext).isScreenOn();
         setEnableMarquee(screenOn);
+        // Allow long-press anywhere else in this view to show the seek bar
+        setOnLongClickListener(mTransportShowSeekBarListener);
     }
 
     @Override
@@ -326,7 +376,6 @@
         mAudioManager.unregisterRemoteController(mRemoteController);
         KeyguardUpdateMonitor.getInstance(mContext).removeCallback(mUpdateMonitor);
         mMetadata.clear();
-        mUserSeeking = false;
         removeCallbacks(mUpdateSeekBars);
     }
 
@@ -484,18 +533,12 @@
 
     void updateSeekDisplay() {
         if (mMetadata != null && mRemoteController != null && mFormat != null) {
-            if (mTimeElapsed == null) {
-                mTimeElapsed = new Date();
-            }
-            if (mTrackDuration == null) {
-                mTrackDuration = new Date();
-            }
-            mTimeElapsed.setTime(mRemoteController.getEstimatedMediaPosition());
-            mTrackDuration.setTime(mMetadata.duration);
-            mTransientSeekTimeElapsed.setText(mFormat.format(mTimeElapsed));
-            mTransientSeekTimeTotal.setText(mFormat.format(mTrackDuration));
+            mTempDate.setTime(mRemoteController.getEstimatedMediaPosition());
+            mTransientSeekTimeElapsed.setText(mFormat.format(mTempDate));
+            mTempDate.setTime(mMetadata.duration);
+            mTransientSeekTimeTotal.setText(mFormat.format(mTempDate));
 
-            if (DEBUG) Log.d(TAG, "updateSeekDisplay timeElapsed=" + mTimeElapsed +
+            if (DEBUG) Log.d(TAG, "updateSeekDisplay timeElapsed=" + mTempDate +
                     " duration=" + mMetadata.duration);
         }
     }
@@ -508,10 +551,16 @@
             mTransientSeek.setVisibility(INVISIBLE);
             mMetadataContainer.setVisibility(VISIBLE);
             cancelResetToMetadata();
+            removeCallbacks(mUpdateSeekBars); // don't update if scrubber isn't visible
         } else {
             mTransientSeek.setVisibility(VISIBLE);
             mMetadataContainer.setVisibility(INVISIBLE);
             delayResetToMetadata();
+            if (playbackPositionShouldMove(mCurrentPlayState)) {
+                mUpdateSeekBars.run();
+            } else {
+                mUpdateSeekBars.updateOnce();
+            }
         }
         mTransportControlCallback.userActivity();
         return true;
@@ -573,9 +622,6 @@
             case RemoteControlClient.PLAYSTATE_PLAYING:
                 imageResId = R.drawable.ic_media_pause;
                 imageDescId = R.string.keyguard_transport_pause_description;
-                if (mSeekEnabled) {
-                    mUpdateSeekBars.run();
-                }
                 break;
 
             case RemoteControlClient.PLAYSTATE_BUFFERING:
@@ -590,10 +636,9 @@
                 break;
         }
 
-        if (state != RemoteControlClient.PLAYSTATE_PLAYING) {
-            removeCallbacks(mUpdateSeekBars);
-            updateSeekBars();
-        }
+        boolean clientSupportsSeek = mMetadata != null && mMetadata.duration > 0;
+        setSeekBarsEnabled(clientSupportsSeek);
+
         mBtnPlay.setImageResource(imageResId);
         mBtnPlay.setContentDescription(getResources().getString(imageDescId));
         mCurrentPlayState = state;
@@ -601,11 +646,9 @@
 
     boolean updateSeekBars() {
         final int position = (int) mRemoteController.getEstimatedMediaPosition();
+        if (DEBUG) Log.v(TAG, "Estimated time:" + position);
         if (position >= 0) {
-            if (DEBUG) Log.v(TAG, "Seek to " + position);
-            if (!mUserSeeking) {
-                mTransientSeekBar.setProgress(position);
-            }
+            mTransientSeekBar.setProgress(position);
             return true;
         }
         Log.w(TAG, "Updating seek bars; received invalid estimated media position (" +
@@ -671,34 +714,4 @@
     public boolean providesClock() {
         return false;
     }
-
-    private boolean wasPlayingRecently(int state, long stateChangeTimeMs) {
-        switch (state) {
-            case RemoteControlClient.PLAYSTATE_PLAYING:
-            case RemoteControlClient.PLAYSTATE_FAST_FORWARDING:
-            case RemoteControlClient.PLAYSTATE_REWINDING:
-            case RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS:
-            case RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS:
-            case RemoteControlClient.PLAYSTATE_BUFFERING:
-                // actively playing or about to play
-                return true;
-            case RemoteControlClient.PLAYSTATE_NONE:
-                return false;
-            case RemoteControlClient.PLAYSTATE_STOPPED:
-            case RemoteControlClient.PLAYSTATE_PAUSED:
-            case RemoteControlClient.PLAYSTATE_ERROR:
-                // we have stopped playing, check how long ago
-                if (DEBUG) {
-                    if ((SystemClock.elapsedRealtime() - stateChangeTimeMs) < DISPLAY_TIMEOUT_MS) {
-                        Log.v(TAG, "wasPlayingRecently: time < TIMEOUT was playing recently");
-                    } else {
-                        Log.v(TAG, "wasPlayingRecently: time > TIMEOUT");
-                    }
-                }
-                return ((SystemClock.elapsedRealtime() - stateChangeTimeMs) < DISPLAY_TIMEOUT_MS);
-            default:
-                Log.e(TAG, "Unknown playback state " + state + " in wasPlayingRecently()");
-                return false;
-        }
-    }
 }
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardViewManager.java b/packages/Keyguard/src/com/android/keyguard/KeyguardViewManager.java
index fd7cae6..6aa0a4b 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardViewManager.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardViewManager.java
@@ -61,9 +61,11 @@
 public class KeyguardViewManager {
     private final static boolean DEBUG = KeyguardViewMediator.DEBUG;
     private static String TAG = "KeyguardViewManager";
-    public static boolean USE_UPPER_CASE = true;
     public final static String IS_SWITCHING_USER = "is_switching_user";
 
+    // Delay dismissing keyguard to allow animations to complete.
+    private static final int HIDE_KEYGUARD_DELAY = 500;
+
     // Timeout used for keypresses
     static final int DIGIT_PRESS_WAKE_MILLIS = 5000;
 
@@ -509,9 +511,10 @@
                             mKeyguardHost.setCustomBackground(null);
                             updateShowWallpaper(true);
                             mKeyguardHost.removeView(lastView);
+                            mViewMediatorCallback.keyguardGone();
                         }
                     }
-                }, 500);
+                }, HIDE_KEYGUARD_DELAY);
             }
         }
     }
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardViewMediator.java b/packages/Keyguard/src/com/android/keyguard/KeyguardViewMediator.java
index b92ae90..49982ea 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardViewMediator.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardViewMediator.java
@@ -253,6 +253,11 @@
     private final float mLockSoundVolume;
 
     /**
+     * For managing external displays
+     */
+    private KeyguardDisplayManager mKeyguardDisplayManager;
+
+    /**
      * Cache of avatar drawables, for use by KeyguardMultiUserAvatar.
      */
     private static MultiUserAvatarCache sMultiUserAvatarCache = new MultiUserAvatarCache();
@@ -304,6 +309,11 @@
          * Report that the keyguard is dismissable, pending the next keyguardDone call.
          */
         void keyguardDonePending();
+
+        /**
+         * Report when keyguard is actually gone
+         */
+        void keyguardGone();
     }
 
     KeyguardUpdateMonitorCallback mUpdateCallback = new KeyguardUpdateMonitorCallback() {
@@ -457,6 +467,11 @@
         public void keyguardDonePending() {
             mKeyguardDonePending = true;
         }
+
+        @Override
+        public void keyguardGone() {
+            mKeyguardDisplayManager.hide();
+        }
     };
 
     private void userActivity() {
@@ -483,6 +498,8 @@
 
         mContext.registerReceiver(mBroadcastReceiver, new IntentFilter(DELAYED_KEYGUARD_ACTION));
 
+        mKeyguardDisplayManager = new KeyguardDisplayManager(context);
+
         mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
 
         mUpdateMonitor = KeyguardUpdateMonitor.getInstance(context);
@@ -597,6 +614,7 @@
             }
         }
         KeyguardUpdateMonitor.getInstance(mContext).dispatchScreenTurndOff(why);
+        mKeyguardDisplayManager.show();
     }
 
     private void doKeyguardLaterLocked() {
@@ -1218,6 +1236,7 @@
 
             mShowKeyguardWakeLock.release();
         }
+        mKeyguardDisplayManager.show();
     }
 
     /**
diff --git a/packages/PrintSpooler/res/values-af/strings.xml b/packages/PrintSpooler/res/values-af/strings.xml
index b8287ae..a10a5a0 100644
--- a/packages/PrintSpooler/res/values-af/strings.xml
+++ b/packages/PrintSpooler/res/values-af/strings.xml
@@ -41,6 +41,8 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Soekkassie vertoon"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Soekkassie weggesteek"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Voeg drukker by"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"Kies drukker"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"Vergeet drukker"</string>
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> drukker gekry"</item>
     <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> drukkers gekry"</item>
diff --git a/packages/PrintSpooler/res/values-am/strings.xml b/packages/PrintSpooler/res/values-am/strings.xml
index d73cdd9..ae3d1f3 100644
--- a/packages/PrintSpooler/res/values-am/strings.xml
+++ b/packages/PrintSpooler/res/values-am/strings.xml
@@ -41,6 +41,10 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"የፍለጋ ሳጥን ይታያል"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"የፍለጋ ሳጥን ተደብቋል"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"አታሚ አክል"</string>
+    <!-- no translation found for print_select_printer (7388760939873368698) -->
+    <skip />
+    <!-- no translation found for print_forget_printer (5035287497291910766) -->
+    <skip />
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> አታሚ ተገኝቷል"</item>
     <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> አታሚዎች ተገኝተዋል"</item>
diff --git a/packages/PrintSpooler/res/values-ar/strings.xml b/packages/PrintSpooler/res/values-ar/strings.xml
index 14b6467..9be03cd 100644
--- a/packages/PrintSpooler/res/values-ar/strings.xml
+++ b/packages/PrintSpooler/res/values-ar/strings.xml
@@ -41,6 +41,8 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"تم إظهار مربع البحث"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"تم إخفاء مربع البحث"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"إضافة طابعة"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"حدد الطابعة"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"تجاهل الطابعة"</string>
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"تم العثور على <xliff:g id="COUNT">%1$s</xliff:g> طابعة"</item>
     <item quantity="other" msgid="6533817036607128241">"تم العثور على <xliff:g id="COUNT">%1$s</xliff:g> من الطابعات"</item>
diff --git a/packages/PrintSpooler/res/values-bg/strings.xml b/packages/PrintSpooler/res/values-bg/strings.xml
index 47f86c6..85b96f32 100644
--- a/packages/PrintSpooler/res/values-bg/strings.xml
+++ b/packages/PrintSpooler/res/values-bg/strings.xml
@@ -41,6 +41,10 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Полето за търсене е показано"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Полето за търсене е скрито"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Добавяне на принтер"</string>
+    <!-- no translation found for print_select_printer (7388760939873368698) -->
+    <skip />
+    <!-- no translation found for print_forget_printer (5035287497291910766) -->
+    <skip />
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"Намерен е <xliff:g id="COUNT">%1$s</xliff:g> принтер"</item>
     <item quantity="other" msgid="6533817036607128241">"Намерени са <xliff:g id="COUNT">%1$s</xliff:g> принтера"</item>
diff --git a/packages/PrintSpooler/res/values-ca/strings.xml b/packages/PrintSpooler/res/values-ca/strings.xml
index fc60b0a..a429dd5 100644
--- a/packages/PrintSpooler/res/values-ca/strings.xml
+++ b/packages/PrintSpooler/res/values-ca/strings.xml
@@ -41,6 +41,8 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Es mostra el quadre de cerca"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"S\'ha amagat el quadre de cerca"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Afegeix una impressora"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"Selecciona una impressora"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"Oblida la impressora"</string>
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"S\'ha trobat <xliff:g id="COUNT">%1$s</xliff:g> impressora"</item>
     <item quantity="other" msgid="6533817036607128241">"S\'han trobat <xliff:g id="COUNT">%1$s</xliff:g> impressores"</item>
diff --git a/packages/PrintSpooler/res/values-cs/strings.xml b/packages/PrintSpooler/res/values-cs/strings.xml
index 3f806d6..e85ea9b 100644
--- a/packages/PrintSpooler/res/values-cs/strings.xml
+++ b/packages/PrintSpooler/res/values-cs/strings.xml
@@ -41,6 +41,10 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Vyhledávací pole se zobrazuje"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Vyhledávací pole je skryto"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Přidat tiskárnu"</string>
+    <!-- no translation found for print_select_printer (7388760939873368698) -->
+    <skip />
+    <!-- no translation found for print_forget_printer (5035287497291910766) -->
+    <skip />
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"Počet nalezených tiskáren: <xliff:g id="COUNT">%1$s</xliff:g>"</item>
     <item quantity="other" msgid="6533817036607128241">"Počet nalezených tiskáren: <xliff:g id="COUNT">%1$s</xliff:g>"</item>
diff --git a/packages/PrintSpooler/res/values-da/strings.xml b/packages/PrintSpooler/res/values-da/strings.xml
index 60c22bb..74190b4 100644
--- a/packages/PrintSpooler/res/values-da/strings.xml
+++ b/packages/PrintSpooler/res/values-da/strings.xml
@@ -41,6 +41,8 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Søgefeltet vises"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Søgefeltet er skjult"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Tilføj printer"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"Vælg printer"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"Glem printer"</string>
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"Der blev fundet <xliff:g id="COUNT">%1$s</xliff:g> printer"</item>
     <item quantity="other" msgid="6533817036607128241">"Der blev fundet <xliff:g id="COUNT">%1$s</xliff:g> printere"</item>
diff --git a/packages/PrintSpooler/res/values-de/strings.xml b/packages/PrintSpooler/res/values-de/strings.xml
index 54c936f..21289e0 100644
--- a/packages/PrintSpooler/res/values-de/strings.xml
+++ b/packages/PrintSpooler/res/values-de/strings.xml
@@ -41,6 +41,10 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Suchfeld angezeigt"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Suchfeld ausgeblendet"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Drucker hinzufügen"</string>
+    <!-- no translation found for print_select_printer (7388760939873368698) -->
+    <skip />
+    <!-- no translation found for print_forget_printer (5035287497291910766) -->
+    <skip />
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> Drucker gefunden"</item>
     <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> Drucker gefunden"</item>
diff --git a/packages/PrintSpooler/res/values-el/strings.xml b/packages/PrintSpooler/res/values-el/strings.xml
index 168f87b..795e730 100644
--- a/packages/PrintSpooler/res/values-el/strings.xml
+++ b/packages/PrintSpooler/res/values-el/strings.xml
@@ -41,6 +41,8 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Εμφάνιση πλαισίου αναζήτησης"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Απόκρυψη πλαισίου αναζήτησης"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Προσθήκη εκτυπωτή"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"Επιλογή εκτυπωτή"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"Διαγραφή εκτυπωτή"</string>
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"Βρέθηκε <xliff:g id="COUNT">%1$s</xliff:g> εκτυπωτής"</item>
     <item quantity="other" msgid="6533817036607128241">"Βρέθηκαν <xliff:g id="COUNT">%1$s</xliff:g> εκτυπωτές"</item>
diff --git a/packages/PrintSpooler/res/values-en-rGB/strings.xml b/packages/PrintSpooler/res/values-en-rGB/strings.xml
index 98c3688..27372f8 100644
--- a/packages/PrintSpooler/res/values-en-rGB/strings.xml
+++ b/packages/PrintSpooler/res/values-en-rGB/strings.xml
@@ -41,6 +41,8 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Search box shown"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Search box hidden"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Add printer"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"Select printer"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"Forget printer"</string>
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> printer found"</item>
     <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> printers found"</item>
diff --git a/packages/PrintSpooler/res/values-en-rIN/strings.xml b/packages/PrintSpooler/res/values-en-rIN/strings.xml
index 98c3688..27372f8 100644
--- a/packages/PrintSpooler/res/values-en-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-en-rIN/strings.xml
@@ -41,6 +41,8 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Search box shown"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Search box hidden"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Add printer"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"Select printer"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"Forget printer"</string>
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> printer found"</item>
     <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> printers found"</item>
diff --git a/packages/PrintSpooler/res/values-es-rUS/strings.xml b/packages/PrintSpooler/res/values-es-rUS/strings.xml
index bfdf933..1fd174d 100644
--- a/packages/PrintSpooler/res/values-es-rUS/strings.xml
+++ b/packages/PrintSpooler/res/values-es-rUS/strings.xml
@@ -41,6 +41,10 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Cuadro de búsqueda visible"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Cuadro de búsqueda oculto"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Agregar impresora"</string>
+    <!-- no translation found for print_select_printer (7388760939873368698) -->
+    <skip />
+    <!-- no translation found for print_forget_printer (5035287497291910766) -->
+    <skip />
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"Se encontró <xliff:g id="COUNT">%1$s</xliff:g> impresora."</item>
     <item quantity="other" msgid="6533817036607128241">"Se encontraron <xliff:g id="COUNT">%1$s</xliff:g> impresoras."</item>
diff --git a/packages/PrintSpooler/res/values-es/strings.xml b/packages/PrintSpooler/res/values-es/strings.xml
index 28df5f0..0225cad 100644
--- a/packages/PrintSpooler/res/values-es/strings.xml
+++ b/packages/PrintSpooler/res/values-es/strings.xml
@@ -41,6 +41,8 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Cuadro de búsqueda visible"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Cuadro de búsqueda oculto"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Añadir impresora"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"Seleccionar impresora"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"Borrar impresora"</string>
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"Se ha encontrado <xliff:g id="COUNT">%1$s</xliff:g> impresora"</item>
     <item quantity="other" msgid="6533817036607128241">"Se han encontrado <xliff:g id="COUNT">%1$s</xliff:g> impresoras"</item>
diff --git a/packages/PrintSpooler/res/values-et-rEE/strings.xml b/packages/PrintSpooler/res/values-et-rEE/strings.xml
index 1114f9f..f4391c8 100644
--- a/packages/PrintSpooler/res/values-et-rEE/strings.xml
+++ b/packages/PrintSpooler/res/values-et-rEE/strings.xml
@@ -41,6 +41,10 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Otsingukast on kuvatud"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Otsingukast on peidetud"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Lisa printer"</string>
+    <!-- no translation found for print_select_printer (7388760939873368698) -->
+    <skip />
+    <!-- no translation found for print_forget_printer (5035287497291910766) -->
+    <skip />
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"Leiti <xliff:g id="COUNT">%1$s</xliff:g> printer"</item>
     <item quantity="other" msgid="6533817036607128241">"Leiti <xliff:g id="COUNT">%1$s</xliff:g> printerit"</item>
diff --git a/packages/PrintSpooler/res/values-fa/strings.xml b/packages/PrintSpooler/res/values-fa/strings.xml
index 950ef92..9db965f 100644
--- a/packages/PrintSpooler/res/values-fa/strings.xml
+++ b/packages/PrintSpooler/res/values-fa/strings.xml
@@ -41,6 +41,10 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"کادر جستجو نمایان شد"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"کادر جستجو پنهان شد"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"افزودن چاپگر"</string>
+    <!-- no translation found for print_select_printer (7388760939873368698) -->
+    <skip />
+    <!-- no translation found for print_forget_printer (5035287497291910766) -->
+    <skip />
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> چاپگر یافت شد"</item>
     <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> چاپگر یافت شد"</item>
diff --git a/packages/PrintSpooler/res/values-fi/strings.xml b/packages/PrintSpooler/res/values-fi/strings.xml
index 239afcf..bb43b6c 100644
--- a/packages/PrintSpooler/res/values-fi/strings.xml
+++ b/packages/PrintSpooler/res/values-fi/strings.xml
@@ -41,6 +41,10 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Hakukenttä näkyvissä"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Hakukenttä piilotettu"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Lisää tulostin"</string>
+    <!-- no translation found for print_select_printer (7388760939873368698) -->
+    <skip />
+    <!-- no translation found for print_forget_printer (5035287497291910766) -->
+    <skip />
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"Löytyi <xliff:g id="COUNT">%1$s</xliff:g> tulostin"</item>
     <item quantity="other" msgid="6533817036607128241">"Löytyi <xliff:g id="COUNT">%1$s</xliff:g> tulostinta"</item>
diff --git a/packages/PrintSpooler/res/values-fr-rCA/strings.xml b/packages/PrintSpooler/res/values-fr-rCA/strings.xml
index 3880745..f42d85f6 100644
--- a/packages/PrintSpooler/res/values-fr-rCA/strings.xml
+++ b/packages/PrintSpooler/res/values-fr-rCA/strings.xml
@@ -41,6 +41,10 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Champ de recherche affiché"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Champ de recherche masqué"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Ajouter une imprimante"</string>
+    <!-- no translation found for print_select_printer (7388760939873368698) -->
+    <skip />
+    <!-- no translation found for print_forget_printer (5035287497291910766) -->
+    <skip />
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> imprimante trouvée"</item>
     <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> imprimantes trouvées"</item>
diff --git a/packages/PrintSpooler/res/values-fr/strings.xml b/packages/PrintSpooler/res/values-fr/strings.xml
index 961d344..39e7493 100644
--- a/packages/PrintSpooler/res/values-fr/strings.xml
+++ b/packages/PrintSpooler/res/values-fr/strings.xml
@@ -41,6 +41,10 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Champ de recherche affiché."</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Champ de recherche masqué."</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Ajouter une imprimante"</string>
+    <!-- no translation found for print_select_printer (7388760939873368698) -->
+    <skip />
+    <!-- no translation found for print_forget_printer (5035287497291910766) -->
+    <skip />
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> imprimante trouvée."</item>
     <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> imprimantes trouvées."</item>
diff --git a/packages/PrintSpooler/res/values-hi/strings.xml b/packages/PrintSpooler/res/values-hi/strings.xml
index 4d1ddd8..af5745f 100644
--- a/packages/PrintSpooler/res/values-hi/strings.xml
+++ b/packages/PrintSpooler/res/values-hi/strings.xml
@@ -41,6 +41,10 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"खोज बॉक्स प्रदर्शित है"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"खोज बॉक्स छिपा हुआ है"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"प्रिंटर जोड़ें"</string>
+    <!-- no translation found for print_select_printer (7388760939873368698) -->
+    <skip />
+    <!-- no translation found for print_forget_printer (5035287497291910766) -->
+    <skip />
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> प्रिंटर मिला"</item>
     <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> प्रिंटर मिले"</item>
diff --git a/packages/PrintSpooler/res/values-hr/strings.xml b/packages/PrintSpooler/res/values-hr/strings.xml
index 50b56ff..ccc4664 100644
--- a/packages/PrintSpooler/res/values-hr/strings.xml
+++ b/packages/PrintSpooler/res/values-hr/strings.xml
@@ -41,6 +41,10 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Okvir za pretraživanje prikazan je"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Okvir za pretraživanje skriven je"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Dodaj pisač"</string>
+    <!-- no translation found for print_select_printer (7388760939873368698) -->
+    <skip />
+    <!-- no translation found for print_forget_printer (5035287497291910766) -->
+    <skip />
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"Pronađen je <xliff:g id="COUNT">%1$s</xliff:g> pisač"</item>
     <item quantity="other" msgid="6533817036607128241">"Pronađen je sljedeći broj pisača: <xliff:g id="COUNT">%1$s</xliff:g>"</item>
diff --git a/packages/PrintSpooler/res/values-hu/strings.xml b/packages/PrintSpooler/res/values-hu/strings.xml
index 79912fc..6a0741b 100644
--- a/packages/PrintSpooler/res/values-hu/strings.xml
+++ b/packages/PrintSpooler/res/values-hu/strings.xml
@@ -41,6 +41,8 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Keresőmező megjelenítve"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Keresőmező elrejtve"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Nyomtató hozzáadása"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"Nyomtató kiválasztása"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"Nyomtató elfelejtése"</string>
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> nyomtató észlelve"</item>
     <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> nyomtató észlelve"</item>
diff --git a/packages/PrintSpooler/res/values-hy-rAM/strings.xml b/packages/PrintSpooler/res/values-hy-rAM/strings.xml
index 7d95f7b..1fe3e2c 100644
--- a/packages/PrintSpooler/res/values-hy-rAM/strings.xml
+++ b/packages/PrintSpooler/res/values-hy-rAM/strings.xml
@@ -41,6 +41,10 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Որոնման վանդակը ցուցադրված է"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Որոնման վանդակը թաքցվել է"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Ավելացնել տպիչ"</string>
+    <!-- no translation found for print_select_printer (7388760939873368698) -->
+    <skip />
+    <!-- no translation found for print_forget_printer (5035287497291910766) -->
+    <skip />
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> տպիչ է գտնվել"</item>
     <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> տպիչ է գտնվել"</item>
diff --git a/packages/PrintSpooler/res/values-in/strings.xml b/packages/PrintSpooler/res/values-in/strings.xml
index 1206676..26c9c33 100644
--- a/packages/PrintSpooler/res/values-in/strings.xml
+++ b/packages/PrintSpooler/res/values-in/strings.xml
@@ -41,6 +41,10 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Kotak telusur ditampilkan"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Kotak telusur disembunyikan"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Tambahkan printer"</string>
+    <!-- no translation found for print_select_printer (7388760939873368698) -->
+    <skip />
+    <!-- no translation found for print_forget_printer (5035287497291910766) -->
+    <skip />
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> printer ditemukan"</item>
     <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> printer ditemukan"</item>
diff --git a/packages/PrintSpooler/res/values-it/strings.xml b/packages/PrintSpooler/res/values-it/strings.xml
index 4223188..96c3b48 100644
--- a/packages/PrintSpooler/res/values-it/strings.xml
+++ b/packages/PrintSpooler/res/values-it/strings.xml
@@ -41,6 +41,8 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Casella di ricerca visualizzata"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Casella di ricerca nascosta"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Aggiungi stampante"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"Seleziona stampante"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"Elimina stampante"</string>
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> stampante trovata"</item>
     <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> stampanti trovate"</item>
diff --git a/packages/PrintSpooler/res/values-iw/strings.xml b/packages/PrintSpooler/res/values-iw/strings.xml
index 2a9e0df..3e0e732 100644
--- a/packages/PrintSpooler/res/values-iw/strings.xml
+++ b/packages/PrintSpooler/res/values-iw/strings.xml
@@ -41,6 +41,8 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"תיבת החיפוש מוצגת"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"תיבת החיפוש מוסתרת"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"הוסף מדפסת"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"בחר מדפסת"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"שכח את המדפסת"</string>
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"נמצאה מדפסת <xliff:g id="COUNT">%1$s</xliff:g>"</item>
     <item quantity="other" msgid="6533817036607128241">"נמצאו <xliff:g id="COUNT">%1$s</xliff:g> מדפסות"</item>
diff --git a/packages/PrintSpooler/res/values-ja/strings.xml b/packages/PrintSpooler/res/values-ja/strings.xml
index e6ae97a..6df1f2b1 100644
--- a/packages/PrintSpooler/res/values-ja/strings.xml
+++ b/packages/PrintSpooler/res/values-ja/strings.xml
@@ -41,6 +41,10 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"検索ボックスは表示されています"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"検索ボックスは表示されていません"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"プリンタを追加"</string>
+    <!-- no translation found for print_select_printer (7388760939873368698) -->
+    <skip />
+    <!-- no translation found for print_forget_printer (5035287497291910766) -->
+    <skip />
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g>台のプリンタが見つかりました"</item>
     <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g>台のプリンタが見つかりました"</item>
diff --git a/packages/PrintSpooler/res/values-ka-rGE/strings.xml b/packages/PrintSpooler/res/values-ka-rGE/strings.xml
index 3fc1f3a..5ffa81e 100644
--- a/packages/PrintSpooler/res/values-ka-rGE/strings.xml
+++ b/packages/PrintSpooler/res/values-ka-rGE/strings.xml
@@ -41,6 +41,10 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"საძიებო ველი ნაჩვენებია"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"საძიებო ველი დამალულია"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"პრინტერის დამატება"</string>
+    <!-- no translation found for print_select_printer (7388760939873368698) -->
+    <skip />
+    <!-- no translation found for print_forget_printer (5035287497291910766) -->
+    <skip />
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"ნაპოვნია <xliff:g id="COUNT">%1$s</xliff:g> პრინტერი"</item>
     <item quantity="other" msgid="6533817036607128241">"ნაპოვნია <xliff:g id="COUNT">%1$s</xliff:g> პრინტერი"</item>
diff --git a/packages/PrintSpooler/res/values-km-rKH/strings.xml b/packages/PrintSpooler/res/values-km-rKH/strings.xml
index 8ed85273..c00dee5 100644
--- a/packages/PrintSpooler/res/values-km-rKH/strings.xml
+++ b/packages/PrintSpooler/res/values-km-rKH/strings.xml
@@ -41,6 +41,10 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"បាន​បង្ហាញ​ប្រ​អប់​ស្វែងរក"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"បាន​លាក់​ប្រអប់​ស្វែងរក"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"បន្ថែម​ម៉ាស៊ីន​បោះពុម្ព"</string>
+    <!-- no translation found for print_select_printer (7388760939873368698) -->
+    <skip />
+    <!-- no translation found for print_forget_printer (5035287497291910766) -->
+    <skip />
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"រក​ឃើញ​ម៉ាស៊ីន​បោះពុម្ព <xliff:g id="COUNT">%1$s</xliff:g>"</item>
     <item quantity="other" msgid="6533817036607128241">"រក​ឃើញ​ម៉ាស៊ីន​បោះពុម្ព <xliff:g id="COUNT">%1$s</xliff:g>"</item>
diff --git a/packages/PrintSpooler/res/values-ko/strings.xml b/packages/PrintSpooler/res/values-ko/strings.xml
index 83155fd..64c7ca6 100644
--- a/packages/PrintSpooler/res/values-ko/strings.xml
+++ b/packages/PrintSpooler/res/values-ko/strings.xml
@@ -41,6 +41,10 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"검색창 표시됨"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"검색창 숨겨짐"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"프린터 추가"</string>
+    <!-- no translation found for print_select_printer (7388760939873368698) -->
+    <skip />
+    <!-- no translation found for print_forget_printer (5035287497291910766) -->
+    <skip />
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"프린터 <xliff:g id="COUNT">%1$s</xliff:g>대 검색됨"</item>
     <item quantity="other" msgid="6533817036607128241">"프린터 <xliff:g id="COUNT">%1$s</xliff:g>대 검색됨"</item>
diff --git a/packages/PrintSpooler/res/values-lo-rLA/strings.xml b/packages/PrintSpooler/res/values-lo-rLA/strings.xml
index 45bb9bc..f954606 100644
--- a/packages/PrintSpooler/res/values-lo-rLA/strings.xml
+++ b/packages/PrintSpooler/res/values-lo-rLA/strings.xml
@@ -41,6 +41,8 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"ກ່ອງຊອກຫາຖືກສະແດງ"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"ກ່ອງຊອກຫາຖືກເຊື່ອງ"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"ເພີ່ມເຄື່ອງພິມ"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"ເລືອກເຄື່ອງພິມ"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"ລືມເຄື່ອງພິມ"</string>
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"ພົບ <xliff:g id="COUNT">%1$s</xliff:g> ເຄື່ອງພິມ"</item>
     <item quantity="other" msgid="6533817036607128241">"ພົບ <xliff:g id="COUNT">%1$s</xliff:g> ເຄື່ອງພິມ"</item>
diff --git a/packages/PrintSpooler/res/values-lt/strings.xml b/packages/PrintSpooler/res/values-lt/strings.xml
index 1560dce..0c4e386 100644
--- a/packages/PrintSpooler/res/values-lt/strings.xml
+++ b/packages/PrintSpooler/res/values-lt/strings.xml
@@ -41,6 +41,8 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Paieškos laukelis rodomas"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Paieškos laukelis paslėptas"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Pridėti spausdintuvą"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"Pasirinkti spausdintuvą"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"Pamiršti spausdintuvą"</string>
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"Rasta spausdintuvų: <xliff:g id="COUNT">%1$s</xliff:g>"</item>
     <item quantity="other" msgid="6533817036607128241">"Rasta spausdintuvų: <xliff:g id="COUNT">%1$s</xliff:g>"</item>
diff --git a/packages/PrintSpooler/res/values-lv/strings.xml b/packages/PrintSpooler/res/values-lv/strings.xml
index 3a6049c..3fffdfe 100644
--- a/packages/PrintSpooler/res/values-lv/strings.xml
+++ b/packages/PrintSpooler/res/values-lv/strings.xml
@@ -41,6 +41,8 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Meklēšanas lodziņš ir redzams."</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Meklēšanas lodziņš ir paslēpts."</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Pievienot printeri"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"Atlasīt printeri"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"Neatcerēties printeri"</string>
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"Atrasts <xliff:g id="COUNT">%1$s</xliff:g> printeris"</item>
     <item quantity="other" msgid="6533817036607128241">"Atrasti <xliff:g id="COUNT">%1$s</xliff:g> printeri"</item>
diff --git a/packages/PrintSpooler/res/values-mn-rMN/strings.xml b/packages/PrintSpooler/res/values-mn-rMN/strings.xml
index 8062eb1..e429387 100644
--- a/packages/PrintSpooler/res/values-mn-rMN/strings.xml
+++ b/packages/PrintSpooler/res/values-mn-rMN/strings.xml
@@ -41,6 +41,8 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Хайлтын нүдийг гаргах"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Хайлтын нүдийг далдлах"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Принтер нэмэх"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"Принтер сонгох"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"Принтерийг мартах"</string>
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> принтер олдсон"</item>
     <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> принтер олдсон"</item>
diff --git a/packages/PrintSpooler/res/values-ms-rMY/strings.xml b/packages/PrintSpooler/res/values-ms-rMY/strings.xml
index d113749..24059b1 100644
--- a/packages/PrintSpooler/res/values-ms-rMY/strings.xml
+++ b/packages/PrintSpooler/res/values-ms-rMY/strings.xml
@@ -41,6 +41,10 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Kotak carian ditunjukkan"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Kotak carian tersembunyi"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Tambah pencetak"</string>
+    <!-- no translation found for print_select_printer (7388760939873368698) -->
+    <skip />
+    <!-- no translation found for print_forget_printer (5035287497291910766) -->
+    <skip />
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> pencetak ditemui"</item>
     <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> pencetak ditemui"</item>
diff --git a/packages/PrintSpooler/res/values-nb/strings.xml b/packages/PrintSpooler/res/values-nb/strings.xml
index abed60d..1344e11 100644
--- a/packages/PrintSpooler/res/values-nb/strings.xml
+++ b/packages/PrintSpooler/res/values-nb/strings.xml
@@ -41,6 +41,8 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Søkefeltet vises"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Søkefeltet er skjult"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Legg til skriver"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"Velg skriveren"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"Glem skriveren"</string>
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> skriver ble funnet"</item>
     <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> skrivere ble funnet"</item>
diff --git a/packages/PrintSpooler/res/values-nl/strings.xml b/packages/PrintSpooler/res/values-nl/strings.xml
index 3289d12..dc12508 100644
--- a/packages/PrintSpooler/res/values-nl/strings.xml
+++ b/packages/PrintSpooler/res/values-nl/strings.xml
@@ -41,6 +41,8 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Zoekvak weergegeven"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Zoekvak verborgen"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Printer toevoegen"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"Printer selecteren"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"Printer vergeten"</string>
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> printer gevonden"</item>
     <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> printers gevonden"</item>
diff --git a/packages/PrintSpooler/res/values-pl/strings.xml b/packages/PrintSpooler/res/values-pl/strings.xml
index 10cb2e7..fda4c14 100644
--- a/packages/PrintSpooler/res/values-pl/strings.xml
+++ b/packages/PrintSpooler/res/values-pl/strings.xml
@@ -41,6 +41,10 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Pole wyszukiwania jest widoczne"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Pole wyszukiwania jest ukryte"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Dodaj drukarkę"</string>
+    <!-- no translation found for print_select_printer (7388760939873368698) -->
+    <skip />
+    <!-- no translation found for print_forget_printer (5035287497291910766) -->
+    <skip />
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"Znaleziono <xliff:g id="COUNT">%1$s</xliff:g> drukarkę"</item>
     <item quantity="other" msgid="6533817036607128241">"Znalezione drukarki: <xliff:g id="COUNT">%1$s</xliff:g>"</item>
diff --git a/packages/PrintSpooler/res/values-pt-rPT/strings.xml b/packages/PrintSpooler/res/values-pt-rPT/strings.xml
index 630fe03..6bfc395 100644
--- a/packages/PrintSpooler/res/values-pt-rPT/strings.xml
+++ b/packages/PrintSpooler/res/values-pt-rPT/strings.xml
@@ -41,6 +41,8 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Caixa de pesquisa apresentada"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Caixa de pesquisa ocultada"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Adicionar impressora"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"Selecionar impressora"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"Esquecer impressora"</string>
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> impressora encontrada"</item>
     <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> impressoras encontradas"</item>
diff --git a/packages/PrintSpooler/res/values-pt/strings.xml b/packages/PrintSpooler/res/values-pt/strings.xml
index 6e5eab1..ae2603e 100644
--- a/packages/PrintSpooler/res/values-pt/strings.xml
+++ b/packages/PrintSpooler/res/values-pt/strings.xml
@@ -41,6 +41,10 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Caixa de pesquisa exibida"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Caixa de pesquisa oculta"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Adicionar impressora"</string>
+    <!-- no translation found for print_select_printer (7388760939873368698) -->
+    <skip />
+    <!-- no translation found for print_forget_printer (5035287497291910766) -->
+    <skip />
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> impressora encontrada"</item>
     <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> impressoras encontradas"</item>
diff --git a/packages/PrintSpooler/res/values-ro/strings.xml b/packages/PrintSpooler/res/values-ro/strings.xml
index c4d9f8e..94d389a 100644
--- a/packages/PrintSpooler/res/values-ro/strings.xml
+++ b/packages/PrintSpooler/res/values-ro/strings.xml
@@ -41,6 +41,10 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Caseta de căutare este afișată"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Caseta de căutare este ascunsă"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Adăugați o imprimantă"</string>
+    <!-- no translation found for print_select_printer (7388760939873368698) -->
+    <skip />
+    <!-- no translation found for print_forget_printer (5035287497291910766) -->
+    <skip />
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> imprimantă găsită"</item>
     <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> (de) imprimante găsite"</item>
diff --git a/packages/PrintSpooler/res/values-ru/strings.xml b/packages/PrintSpooler/res/values-ru/strings.xml
index b1335a0..5eb2d57 100644
--- a/packages/PrintSpooler/res/values-ru/strings.xml
+++ b/packages/PrintSpooler/res/values-ru/strings.xml
@@ -41,6 +41,10 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Окно поиска показано"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Окно поиска скрыто"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Добавить принтер"</string>
+    <!-- no translation found for print_select_printer (7388760939873368698) -->
+    <skip />
+    <!-- no translation found for print_forget_printer (5035287497291910766) -->
+    <skip />
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"Найден <xliff:g id="COUNT">%1$s</xliff:g> принтер"</item>
     <item quantity="other" msgid="6533817036607128241">"Найдено принтеров: <xliff:g id="COUNT">%1$s</xliff:g>"</item>
diff --git a/packages/PrintSpooler/res/values-sk/strings.xml b/packages/PrintSpooler/res/values-sk/strings.xml
index 922a759..e868078 100644
--- a/packages/PrintSpooler/res/values-sk/strings.xml
+++ b/packages/PrintSpooler/res/values-sk/strings.xml
@@ -41,6 +41,10 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Vyhľadávacie pole sa zobrazuje"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Vyhľadávacie pole je skryté"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Pridať tlačiareň"</string>
+    <!-- no translation found for print_select_printer (7388760939873368698) -->
+    <skip />
+    <!-- no translation found for print_forget_printer (5035287497291910766) -->
+    <skip />
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"Našla sa <xliff:g id="COUNT">%1$s</xliff:g> tlačiareň"</item>
     <item quantity="other" msgid="6533817036607128241">"Počet nájdených tlačiarní: <xliff:g id="COUNT">%1$s</xliff:g>"</item>
diff --git a/packages/PrintSpooler/res/values-sl/strings.xml b/packages/PrintSpooler/res/values-sl/strings.xml
index abd07c6..018f56d 100644
--- a/packages/PrintSpooler/res/values-sl/strings.xml
+++ b/packages/PrintSpooler/res/values-sl/strings.xml
@@ -41,6 +41,10 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Iskalno polje je prikazano"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Iskalno polje je skrito"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Dodajanje tiskalnika"</string>
+    <!-- no translation found for print_select_printer (7388760939873368698) -->
+    <skip />
+    <!-- no translation found for print_forget_printer (5035287497291910766) -->
+    <skip />
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"Najden <xliff:g id="COUNT">%1$s</xliff:g> tiskalnik"</item>
     <item quantity="other" msgid="6533817036607128241">"Število najdenih tiskalnikov: <xliff:g id="COUNT">%1$s</xliff:g>"</item>
diff --git a/packages/PrintSpooler/res/values-sr/strings.xml b/packages/PrintSpooler/res/values-sr/strings.xml
index 24f4797..cbab1a6 100644
--- a/packages/PrintSpooler/res/values-sr/strings.xml
+++ b/packages/PrintSpooler/res/values-sr/strings.xml
@@ -41,6 +41,8 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Оквир за претрагу је приказан"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Оквир за претрагу је сакривен"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Додај штампач"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"Изабери штампач"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"Заборави штампач"</string>
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"Пронађен је <xliff:g id="COUNT">%1$s</xliff:g> штампач"</item>
     <item quantity="other" msgid="6533817036607128241">"Пронађено је <xliff:g id="COUNT">%1$s</xliff:g> штампача"</item>
diff --git a/packages/PrintSpooler/res/values-sv/strings.xml b/packages/PrintSpooler/res/values-sv/strings.xml
index 2d80858..9eb9930 100644
--- a/packages/PrintSpooler/res/values-sv/strings.xml
+++ b/packages/PrintSpooler/res/values-sv/strings.xml
@@ -41,6 +41,10 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Sökrutan visas"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Sökrutan är dold"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Lägg till skrivare"</string>
+    <!-- no translation found for print_select_printer (7388760939873368698) -->
+    <skip />
+    <!-- no translation found for print_forget_printer (5035287497291910766) -->
+    <skip />
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> skrivare hittades"</item>
     <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> skrivare hittades"</item>
diff --git a/packages/PrintSpooler/res/values-sw/strings.xml b/packages/PrintSpooler/res/values-sw/strings.xml
index 3873d37..c99ce0d 100644
--- a/packages/PrintSpooler/res/values-sw/strings.xml
+++ b/packages/PrintSpooler/res/values-sw/strings.xml
@@ -41,6 +41,10 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Kisanduku cha kutafutia kimeonyeshwa"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Kisanduku cha kutafutia kimefichwa"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Ongeza printa"</string>
+    <!-- no translation found for print_select_printer (7388760939873368698) -->
+    <skip />
+    <!-- no translation found for print_forget_printer (5035287497291910766) -->
+    <skip />
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"Printa <xliff:g id="COUNT">%1$s</xliff:g> imepatikana"</item>
     <item quantity="other" msgid="6533817036607128241">"Printa <xliff:g id="COUNT">%1$s</xliff:g> zimepatikana"</item>
diff --git a/packages/PrintSpooler/res/values-th/strings.xml b/packages/PrintSpooler/res/values-th/strings.xml
index 7d6523e..2f3ae1f 100644
--- a/packages/PrintSpooler/res/values-th/strings.xml
+++ b/packages/PrintSpooler/res/values-th/strings.xml
@@ -41,6 +41,10 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"แสดงช่องค้นหาอยู่"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"ซ่อนช่องค้นหาอยู่"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"เพิ่มเครื่องพิมพ์"</string>
+    <!-- no translation found for print_select_printer (7388760939873368698) -->
+    <skip />
+    <!-- no translation found for print_forget_printer (5035287497291910766) -->
+    <skip />
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"พบเครื่องพิมพ์ <xliff:g id="COUNT">%1$s</xliff:g> เครื่อง"</item>
     <item quantity="other" msgid="6533817036607128241">"พบเครื่องพิมพ์ <xliff:g id="COUNT">%1$s</xliff:g> เครื่อง"</item>
diff --git a/packages/PrintSpooler/res/values-tl/strings.xml b/packages/PrintSpooler/res/values-tl/strings.xml
index 238c6bc..7fc1071 100644
--- a/packages/PrintSpooler/res/values-tl/strings.xml
+++ b/packages/PrintSpooler/res/values-tl/strings.xml
@@ -41,6 +41,10 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Ipinapakita ang box para sa paghahanap"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Nakatago ang box para sa paghahanap"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Magdagdag ng printer"</string>
+    <!-- no translation found for print_select_printer (7388760939873368698) -->
+    <skip />
+    <!-- no translation found for print_forget_printer (5035287497291910766) -->
+    <skip />
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> printer ang nakita"</item>
     <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> (na) printer ang nakita"</item>
diff --git a/packages/PrintSpooler/res/values-tr/strings.xml b/packages/PrintSpooler/res/values-tr/strings.xml
index f851f20..1be7a04 100644
--- a/packages/PrintSpooler/res/values-tr/strings.xml
+++ b/packages/PrintSpooler/res/values-tr/strings.xml
@@ -41,6 +41,10 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Arama kutusu gösteriliyor"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Arama kutusu gizli"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Yazıcı ekle"</string>
+    <!-- no translation found for print_select_printer (7388760939873368698) -->
+    <skip />
+    <!-- no translation found for print_forget_printer (5035287497291910766) -->
+    <skip />
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> yazıcı bulundu"</item>
     <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> yazıcı bulundu"</item>
diff --git a/packages/PrintSpooler/res/values-uk/strings.xml b/packages/PrintSpooler/res/values-uk/strings.xml
index 8a340f1..4f526d0 100644
--- a/packages/PrintSpooler/res/values-uk/strings.xml
+++ b/packages/PrintSpooler/res/values-uk/strings.xml
@@ -41,6 +41,8 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Вікно пошуку показано"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Вікно пошуку сховано"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Додати принтер"</string>
+    <string name="print_select_printer" msgid="7388760939873368698">"Вибрати принтер"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"Ігнорувати принтер"</string>
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"Знайдено принтерів: <xliff:g id="COUNT">%1$s</xliff:g>"</item>
     <item quantity="other" msgid="6533817036607128241">"Знайдено принтерів: <xliff:g id="COUNT">%1$s</xliff:g>"</item>
diff --git a/packages/PrintSpooler/res/values-vi/strings.xml b/packages/PrintSpooler/res/values-vi/strings.xml
index 7d086ad..6669e99 100644
--- a/packages/PrintSpooler/res/values-vi/strings.xml
+++ b/packages/PrintSpooler/res/values-vi/strings.xml
@@ -41,6 +41,10 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Hiển thị hộp tìm kiếm"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Ẩn hộp tìm kiếm"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Thêm máy in"</string>
+    <!-- no translation found for print_select_printer (7388760939873368698) -->
+    <skip />
+    <!-- no translation found for print_forget_printer (5035287497291910766) -->
+    <skip />
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"Đã tìm thấy <xliff:g id="COUNT">%1$s</xliff:g> máy in"</item>
     <item quantity="other" msgid="6533817036607128241">"Đã tìm thấy <xliff:g id="COUNT">%1$s</xliff:g> máy in"</item>
diff --git a/packages/PrintSpooler/res/values-zh-rCN/strings.xml b/packages/PrintSpooler/res/values-zh-rCN/strings.xml
index 7e501f1..41f7d65 100644
--- a/packages/PrintSpooler/res/values-zh-rCN/strings.xml
+++ b/packages/PrintSpooler/res/values-zh-rCN/strings.xml
@@ -41,6 +41,10 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"搜索框已显示"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"搜索框已隐藏"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"添加打印机"</string>
+    <!-- no translation found for print_select_printer (7388760939873368698) -->
+    <skip />
+    <!-- no translation found for print_forget_printer (5035287497291910766) -->
+    <skip />
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"找到<xliff:g id="COUNT">%1$s</xliff:g>台打印机"</item>
     <item quantity="other" msgid="6533817036607128241">"找到<xliff:g id="COUNT">%1$s</xliff:g>台打印机"</item>
diff --git a/packages/PrintSpooler/res/values-zh-rHK/strings.xml b/packages/PrintSpooler/res/values-zh-rHK/strings.xml
index 3856c75..9a0a2c9 100644
--- a/packages/PrintSpooler/res/values-zh-rHK/strings.xml
+++ b/packages/PrintSpooler/res/values-zh-rHK/strings.xml
@@ -41,6 +41,10 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"搜尋框已顯示"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"搜尋框已隱藏"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"新增打印機"</string>
+    <!-- no translation found for print_select_printer (7388760939873368698) -->
+    <skip />
+    <!-- no translation found for print_forget_printer (5035287497291910766) -->
+    <skip />
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"找到 <xliff:g id="COUNT">%1$s</xliff:g> 部打印機"</item>
     <item quantity="other" msgid="6533817036607128241">"找到 <xliff:g id="COUNT">%1$s</xliff:g> 部打印機"</item>
diff --git a/packages/PrintSpooler/res/values-zh-rTW/strings.xml b/packages/PrintSpooler/res/values-zh-rTW/strings.xml
index 81e0627..e76774c 100644
--- a/packages/PrintSpooler/res/values-zh-rTW/strings.xml
+++ b/packages/PrintSpooler/res/values-zh-rTW/strings.xml
@@ -41,6 +41,10 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"搜尋框已顯示"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"搜尋框已隱藏"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"新增印表機"</string>
+    <!-- no translation found for print_select_printer (7388760939873368698) -->
+    <skip />
+    <!-- no translation found for print_forget_printer (5035287497291910766) -->
+    <skip />
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"找到 <xliff:g id="COUNT">%1$s</xliff:g> 台印表機"</item>
     <item quantity="other" msgid="6533817036607128241">"找到 <xliff:g id="COUNT">%1$s</xliff:g> 台印表機"</item>
diff --git a/packages/PrintSpooler/res/values-zu/strings.xml b/packages/PrintSpooler/res/values-zu/strings.xml
index 03c499f..3310db8 100644
--- a/packages/PrintSpooler/res/values-zu/strings.xml
+++ b/packages/PrintSpooler/res/values-zu/strings.xml
@@ -41,6 +41,10 @@
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Ibhokisi lokuhlola libonisiwe"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Ibhokisi lokusesha lifihliwe"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Engeza iphrinta"</string>
+    <!-- no translation found for print_select_printer (7388760939873368698) -->
+    <skip />
+    <!-- no translation found for print_forget_printer (5035287497291910766) -->
+    <skip />
   <plurals name="print_search_result_count_utterance">
     <item quantity="one" msgid="4484953260685964252">"<xliff:g id="COUNT">%1$s</xliff:g> iphrinta itholiwe"</item>
     <item quantity="other" msgid="6533817036607128241">"<xliff:g id="COUNT">%1$s</xliff:g> amaphrinta atholiwe"</item>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 556a146..25202edf 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -490,10 +490,8 @@
     <string name="quick_settings_wifi_no_network">No Network</string>
     <!-- QuickSettings: Wifi (Off) [CHAR LIMIT=NONE] -->
     <string name="quick_settings_wifi_off_label">Wi-Fi Off</string>
-    <!-- QuickSettings: Wifi display [CHAR LIMIT=NONE] -->
-    <string name="quick_settings_wifi_display_label">Wi-Fi Display</string>
-    <!-- QuickSettings: Wifi display [CHAR LIMIT=NONE] -->
-    <string name="quick_settings_wifi_display_no_connection_label">Wireless Display</string>
+    <!-- QuickSettings: Remote display [CHAR LIMIT=NONE] -->
+    <string name="quick_settings_remote_display_no_connection_label">Cast Screen</string>
     <!-- QuickSettings: Brightness dialog title [CHAR LIMIT=NONE] -->
     <string name="quick_settings_brightness_dialog_title">Brightness</string>
     <!-- QuickSettings: Brightness dialog auto brightness button [CHAR LIMIT=NONE] -->
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
index 112780b..bb37837 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
@@ -40,7 +40,6 @@
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.LevelListDrawable;
 import android.hardware.display.DisplayManager;
-import android.hardware.display.WifiDisplayStatus;
 import android.net.wifi.WifiManager;
 import android.os.AsyncTask;
 import android.os.Handler;
@@ -94,9 +93,7 @@
     private QuickSettingsModel mModel;
     private ViewGroup mContainerView;
 
-    private DisplayManager mDisplayManager;
     private DevicePolicyManager mDevicePolicyManager;
-    private WifiDisplayStatus mWifiDisplayStatus;
     private PhoneStatusBar mStatusBarService;
     private BluetoothState mBluetoothState;
     private BluetoothAdapter mBluetoothAdapter;
@@ -120,13 +117,11 @@
             new ArrayList<QuickSettingsTileView>();
 
     public QuickSettings(Context context, QuickSettingsContainerView container) {
-        mDisplayManager = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
         mDevicePolicyManager
             = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
         mContext = context;
         mContainerView = container;
         mModel = new QuickSettingsModel(context);
-        mWifiDisplayStatus = new WifiDisplayStatus();
         mBluetoothState = new QuickSettingsModel.BluetoothState();
         mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
         mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
@@ -173,7 +168,6 @@
         mLocationController = locationController;
 
         setupQuickSettings();
-        updateWifiDisplayStatus();
         updateResources();
         applyLocationEnabledStatus();
 
@@ -316,11 +310,19 @@
                 collapsePanels();
                 final UserManager um = UserManager.get(mContext);
                 if (um.getUsers(true).size() > 1) {
-                    try {
-                        WindowManagerGlobal.getWindowManagerService().lockNow(null);
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "Couldn't show user switcher", e);
-                    }
+                    // Since keyguard and systemui were merged into the same process to save
+                    // memory, they share the same Looper and graphics context.  As a result,
+                    // there's no way to allow concurrent animation while keyguard inflates.
+                    // The workaround is to add a slight delay to allow the animation to finish.
+                    mHandler.postDelayed(new Runnable() {
+                        public void run() {
+                            try {
+                                WindowManagerGlobal.getWindowManagerService().lockNow(null);
+                            } catch (RemoteException e) {
+                                Log.e(TAG, "Couldn't show user switcher", e);
+                            }
+                        }
+                    }, 400); // TODO: ideally this would be tied to the collapse of the panel
                 } else {
                     Intent intent = ContactsContract.QuickContact.composeQuickContactsIntent(
                             mContext, v, ContactsContract.Profile.CONTENT_URI,
@@ -699,20 +701,20 @@
         });
         parent.addView(alarmTile);
 
-        // Wifi Display
-        QuickSettingsBasicTile wifiDisplayTile
+        // Remote Display
+        QuickSettingsBasicTile remoteDisplayTile
                 = new QuickSettingsBasicTile(mContext);
-        wifiDisplayTile.setImageResource(R.drawable.ic_qs_remote_display);
-        wifiDisplayTile.setOnClickListener(new View.OnClickListener() {
+        remoteDisplayTile.setImageResource(R.drawable.ic_qs_remote_display);
+        remoteDisplayTile.setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
                 startSettingsActivity(android.provider.Settings.ACTION_WIFI_DISPLAY_SETTINGS);
             }
         });
-        mModel.addWifiDisplayTile(wifiDisplayTile,
-                new QuickSettingsModel.BasicRefreshCallback(wifiDisplayTile)
+        mModel.addRemoteDisplayTile(remoteDisplayTile,
+                new QuickSettingsModel.BasicRefreshCallback(remoteDisplayTile)
                         .setShowWhenEnabled(true));
-        parent.addView(wifiDisplayTile);
+        parent.addView(remoteDisplayTile);
 
         if (SHOW_IME_TILE || DEBUG_GONE_TILES) {
             // IME
@@ -847,15 +849,6 @@
         dialog.show();
     }
 
-    private void updateWifiDisplayStatus() {
-        mWifiDisplayStatus = mDisplayManager.getWifiDisplayStatus();
-        applyWifiDisplayStatus();
-    }
-
-    private void applyWifiDisplayStatus() {
-        mModel.onWifiDisplayStateChanged(mWifiDisplayStatus);
-    }
-
     private void applyBluetoothStatus() {
         mModel.onBluetoothStateChange(mBluetoothState);
     }
@@ -879,12 +872,7 @@
         @Override
         public void onReceive(Context context, Intent intent) {
             final String action = intent.getAction();
-            if (DisplayManager.ACTION_WIFI_DISPLAY_STATUS_CHANGED.equals(action)) {
-                WifiDisplayStatus status = (WifiDisplayStatus)intent.getParcelableExtra(
-                        DisplayManager.EXTRA_WIFI_DISPLAY_STATUS);
-                mWifiDisplayStatus = status;
-                applyWifiDisplayStatus();
-            } else if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) {
+            if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) {
                 int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
                         BluetoothAdapter.ERROR);
                 mBluetoothState.enabled = (state == BluetoothAdapter.STATE_ON);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java
index fa97a11..d8950f4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java
@@ -27,7 +27,8 @@
 import android.content.res.Resources;
 import android.database.ContentObserver;
 import android.graphics.drawable.Drawable;
-import android.hardware.display.WifiDisplayStatus;
+import android.media.MediaRouter;
+import android.media.MediaRouter.RouteInfo;
 import android.net.ConnectivityManager;
 import android.net.Uri;
 import android.os.Handler;
@@ -58,7 +59,6 @@
         BrightnessStateChangeCallback,
         RotationLockControllerCallback,
         LocationSettingsChangeCallback {
-
     // Sett InputMethoManagerService
     private static final String TAG_TRY_SUPPRESSING_IME_SWITCHER = "TrySuppressingImeSwitcher";
 
@@ -294,6 +294,30 @@
         }
     }
 
+    /** Callback for changes to remote display routes. */
+    private class RemoteDisplayRouteCallback extends MediaRouter.SimpleCallback {
+        @Override
+        public void onRouteAdded(MediaRouter router, RouteInfo route) {
+            updateRemoteDisplays();
+        }
+        @Override
+        public void onRouteChanged(MediaRouter router, RouteInfo route) {
+            updateRemoteDisplays();
+        }
+        @Override
+        public void onRouteRemoved(MediaRouter router, RouteInfo route) {
+            updateRemoteDisplays();
+        }
+        @Override
+        public void onRouteSelected(MediaRouter router, int type, RouteInfo route) {
+            updateRemoteDisplays();
+        }
+        @Override
+        public void onRouteUnselected(MediaRouter router, int type, RouteInfo route) {
+            updateRemoteDisplays();
+        }
+    }
+
     private final Context mContext;
     private final Handler mHandler;
     private final CurrentUserTracker mUserTracker;
@@ -304,6 +328,9 @@
     private final DisplayContrastObserver mContrastObserver;
     private final DisplayColorSpaceObserver mColorSpaceObserver;
 
+    private final MediaRouter mMediaRouter;
+    private final RemoteDisplayRouteCallback mRemoteDisplayRouteCallback;
+
     private final boolean mHasMobileData;
 
     private QuickSettingsTileView mUserTile;
@@ -326,9 +353,9 @@
     private RefreshCallback mWifiCallback;
     private WifiState mWifiState = new WifiState();
 
-    private QuickSettingsTileView mWifiDisplayTile;
-    private RefreshCallback mWifiDisplayCallback;
-    private State mWifiDisplayState = new State();
+    private QuickSettingsTileView mRemoteDisplayTile;
+    private RefreshCallback mRemoteDisplayCallback;
+    private State mRemoteDisplayState = new State();
 
     private QuickSettingsTileView mRSSITile;
     private RefreshCallback mRSSICallback;
@@ -401,6 +428,7 @@
                 onColorSpaceChanged();
                 onNextAlarmChanged();
                 onBugreportChanged();
+                rebindMediaRouterAsCurrentUser();
             }
         };
 
@@ -417,6 +445,11 @@
         mColorSpaceObserver = new DisplayColorSpaceObserver(mHandler);
         mColorSpaceObserver.startObserving();
 
+        mMediaRouter = (MediaRouter)context.getSystemService(Context.MEDIA_ROUTER_SERVICE);
+        rebindMediaRouterAsCurrentUser();
+
+        mRemoteDisplayRouteCallback = new RemoteDisplayRouteCallback();
+
         ConnectivityManager cm = (ConnectivityManager)
                 context.getSystemService(Context.CONNECTIVITY_SERVICE);
         mHasMobileData = cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
@@ -744,24 +777,59 @@
         mBugreportCallback.refreshView(mBugreportTile, mBugreportState);
     }
 
-    // Wifi Display
-    void addWifiDisplayTile(QuickSettingsTileView view, RefreshCallback cb) {
-        mWifiDisplayTile = view;
-        mWifiDisplayCallback = cb;
-    }
-    public void onWifiDisplayStateChanged(WifiDisplayStatus status) {
-        mWifiDisplayState.enabled =
-                (status.getFeatureState() == WifiDisplayStatus.FEATURE_STATE_ON);
-        if (status.getActiveDisplay() != null) {
-            mWifiDisplayState.label = status.getActiveDisplay().getFriendlyDisplayName();
-            mWifiDisplayState.iconId = R.drawable.ic_qs_remote_display_connected;
-        } else {
-            mWifiDisplayState.label = mContext.getString(
-                    R.string.quick_settings_wifi_display_no_connection_label);
-            mWifiDisplayState.iconId = R.drawable.ic_qs_remote_display;
-        }
-        mWifiDisplayCallback.refreshView(mWifiDisplayTile, mWifiDisplayState);
+    // Remote Display
+    void addRemoteDisplayTile(QuickSettingsTileView view, RefreshCallback cb) {
+        mRemoteDisplayTile = view;
+        mRemoteDisplayCallback = cb;
+        final int[] count = new int[1];
+        mRemoteDisplayTile.setOnPrepareListener(new QuickSettingsTileView.OnPrepareListener() {
+            @Override
+            public void onPrepare() {
+                mMediaRouter.addCallback(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY,
+                        mRemoteDisplayRouteCallback,
+                        MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY);
+                updateRemoteDisplays();
+            }
+            @Override
+            public void onUnprepare() {
+                mMediaRouter.removeCallback(mRemoteDisplayRouteCallback);
+            }
+        });
 
+        updateRemoteDisplays();
+    }
+
+    private void rebindMediaRouterAsCurrentUser() {
+        mMediaRouter.rebindAsUser(mUserTracker.getCurrentUserId());
+    }
+
+    private void updateRemoteDisplays() {
+        MediaRouter.RouteInfo connectedRoute = mMediaRouter.getSelectedRoute(
+                MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY);
+        boolean enabled = connectedRoute != null && (connectedRoute.getSupportedTypes()
+                & MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY) != 0;
+        if (!enabled) {
+            connectedRoute = null;
+            final int count = mMediaRouter.getRouteCount();
+            for (int i = 0; i < count; i++) {
+                MediaRouter.RouteInfo route = mMediaRouter.getRouteAt(i);
+                if ((route.getSupportedTypes() & MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY) != 0) {
+                    enabled = true;
+                    break;
+                }
+            }
+        }
+
+        mRemoteDisplayState.enabled = enabled;
+        if (connectedRoute != null) {
+            mRemoteDisplayState.label = connectedRoute.getName().toString();
+            mRemoteDisplayState.iconId = R.drawable.ic_qs_remote_display_connected;
+        } else {
+            mRemoteDisplayState.label = mContext.getString(
+                    R.string.quick_settings_remote_display_no_connection_label);
+            mRemoteDisplayState.iconId = R.drawable.ic_qs_remote_display;
+        }
+        mRemoteDisplayCallback.refreshView(mRemoteDisplayTile, mRemoteDisplayState);
     }
 
     // IME
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsTileView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsTileView.java
index 3d520f7..ad18294 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsTileView.java
@@ -21,6 +21,7 @@
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
+import android.view.ViewParent;
 import android.widget.FrameLayout;
 
 /**
@@ -31,14 +32,14 @@
 
     private int mContentLayoutId;
     private int mColSpan;
-    private int mRowSpan;
+    private boolean mPrepared;
+    private OnPrepareListener mOnPrepareListener;
 
     public QuickSettingsTileView(Context context, AttributeSet attrs) {
         super(context, attrs);
 
         mContentLayoutId = -1;
         mColSpan = 1;
-        mRowSpan = 1;
     }
 
     void setColumnSpan(int span) {
@@ -77,4 +78,72 @@
         }
         super.setVisibility(vis);
     }
+
+    public void setOnPrepareListener(OnPrepareListener listener) {
+        if (mOnPrepareListener != listener) {
+            mOnPrepareListener = listener;
+            mPrepared = false;
+            post(new Runnable() {
+                @Override
+                public void run() {
+                    updatePreparedState();
+                }
+            });
+        }
+    }
+
+    @Override
+    protected void onVisibilityChanged(View changedView, int visibility) {
+        super.onVisibilityChanged(changedView, visibility);
+        updatePreparedState();
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        updatePreparedState();
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        updatePreparedState();
+    }
+
+    private void updatePreparedState() {
+        if (mOnPrepareListener != null) {
+            if (isParentVisible()) {
+                if (!mPrepared) {
+                    mPrepared = true;
+                    mOnPrepareListener.onPrepare();
+                }
+            } else if (mPrepared) {
+                mPrepared = false;
+                mOnPrepareListener.onUnprepare();
+            }
+        }
+    }
+
+    private boolean isParentVisible() {
+        if (!isAttachedToWindow()) {
+            return false;
+        }
+        for (ViewParent current = getParent(); current instanceof View;
+                current = current.getParent()) {
+            View view = (View)current;
+            if (view.getVisibility() != VISIBLE) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Called when the view's parent becomes visible or invisible to provide
+     * an opportunity for the client to provide new content.
+     */
+    public interface OnPrepareListener {
+        void onPrepare();
+        void onUnprepare();
+    }
 }
\ No newline at end of file
diff --git a/policy/src/com/android/internal/policy/impl/BarController.java b/policy/src/com/android/internal/policy/impl/BarController.java
index c38ad04..0ce4b12 100644
--- a/policy/src/com/android/internal/policy/impl/BarController.java
+++ b/policy/src/com/android/internal/policy/impl/BarController.java
@@ -37,8 +37,9 @@
     private static final boolean DEBUG = false;
 
     private static final int TRANSIENT_BAR_NONE = 0;
-    private static final int TRANSIENT_BAR_SHOWING = 1;
-    private static final int TRANSIENT_BAR_HIDING = 2;
+    private static final int TRANSIENT_BAR_SHOW_REQUESTED = 1;
+    private static final int TRANSIENT_BAR_SHOWING = 2;
+    private static final int TRANSIENT_BAR_HIDING = 3;
 
     private static final int TRANSLUCENT_ANIMATION_DELAY_MS = 1000;
 
@@ -73,13 +74,9 @@
         mWin = win;
     }
 
-    public boolean isHidden() {
-        return mState == StatusBarManager.WINDOW_STATE_HIDDEN;
-    }
-
     public void showTransient() {
         if (mWin != null) {
-            setTransientBarState(TRANSIENT_BAR_SHOWING);
+            setTransientBarState(TRANSIENT_BAR_SHOW_REQUESTED);
         }
     }
 
@@ -87,6 +84,10 @@
         return mTransientBarState == TRANSIENT_BAR_SHOWING;
     }
 
+    public boolean isTransientShowRequested() {
+        return mTransientBarState == TRANSIENT_BAR_SHOW_REQUESTED;
+    }
+
     public boolean wasRecentlyTranslucent() {
         return (SystemClock.uptimeMillis() - mLastTranslucent) < TRANSLUCENT_ANIMATION_DELAY_MS;
     }
@@ -198,6 +199,9 @@
         if (mTransientBarState == TRANSIENT_BAR_SHOWING) {
             if (DEBUG) Slog.d(mTag, "Not showing transient bar, already shown");
             return false;
+        } else if (mTransientBarState == TRANSIENT_BAR_SHOW_REQUESTED) {
+            if (DEBUG) Slog.d(mTag, "Not showing transient bar, already requested");
+            return false;
         } else if (mWin == null) {
             if (DEBUG) Slog.d(mTag, "Not showing transient bar, bar doesn't exist");
             return false;
@@ -211,12 +215,13 @@
 
     public int updateVisibilityLw(boolean transientAllowed, int oldVis, int vis) {
         if (mWin == null) return vis;
-        if (mTransientBarState == TRANSIENT_BAR_SHOWING) { // transient bar requested
+        if (isTransientShowing() || isTransientShowRequested()) { // transient bar requested
             if (transientAllowed) {
                 vis |= mTransientFlag;
                 if ((oldVis & mTransientFlag) == 0) {
                     vis |= mUnhideFlag;  // tell sysui we're ready to unhide
                 }
+                setTransientBarState(TRANSIENT_BAR_SHOWING);  // request accepted
             } else {
                 setTransientBarState(TRANSIENT_BAR_NONE);  // request denied
             }
@@ -254,6 +259,7 @@
     private static String transientBarStateToString(int state) {
         if (state == TRANSIENT_BAR_HIDING) return "TRANSIENT_BAR_HIDING";
         if (state == TRANSIENT_BAR_SHOWING) return "TRANSIENT_BAR_SHOWING";
+        if (state == TRANSIENT_BAR_SHOW_REQUESTED) return "TRANSIENT_BAR_SHOW_REQUESTED";
         if (state == TRANSIENT_BAR_NONE) return "TRANSIENT_BAR_NONE";
         throw new IllegalArgumentException("Unknown state " + state);
     }
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 1c3304d..8f391b1 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -5146,9 +5146,9 @@
                 mNavigationBar != null &&
                 hideNavBarSysui && immersiveSticky;
 
-        boolean denyTransientStatus = mStatusBarController.isTransientShowing()
+        boolean denyTransientStatus = mStatusBarController.isTransientShowRequested()
                 && !transientStatusBarAllowed && hideStatusBarSysui;
-        boolean denyTransientNav = mNavigationBarController.isTransientShowing()
+        boolean denyTransientNav = mNavigationBarController.isTransientShowRequested()
                 && !transientNavBarAllowed;
         if (denyTransientStatus || denyTransientNav) {
             // clear the clearable flags instead
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index bb14259..a42cbcf 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -55,6 +55,7 @@
 import com.android.server.display.DisplayManagerService;
 import com.android.server.dreams.DreamManagerService;
 import com.android.server.input.InputManagerService;
+import com.android.server.media.MediaRouterService;
 import com.android.server.net.NetworkPolicyManagerService;
 import com.android.server.net.NetworkStatsService;
 import com.android.server.os.SchedulingPolicyService;
@@ -356,6 +357,7 @@
         DreamManagerService dreamy = null;
         AssetAtlasService atlas = null;
         PrintManagerService printManager = null;
+        MediaRouterService mediaRouter = null;
 
         // Bring up services needed for UI.
         if (factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
@@ -804,6 +806,16 @@
             } catch (Throwable e) {
                 reportWtf("starting Print Service", e);
             }
+
+            if (!disableNonCoreServices) {
+                try {
+                    Slog.i(TAG, "Media Router Service");
+                    mediaRouter = new MediaRouterService(context);
+                    ServiceManager.addService(Context.MEDIA_ROUTER_SERVICE, mediaRouter);
+                } catch (Throwable e) {
+                    reportWtf("starting MediaRouterService", e);
+                }
+            }
         }
 
         // Before things start rolling, be sure we have decided whether
@@ -916,6 +928,7 @@
         final InputManagerService inputManagerF = inputManager;
         final TelephonyRegistry telephonyRegistryF = telephonyRegistry;
         final PrintManagerService printManagerF = printManager;
+        final MediaRouterService mediaRouterF = mediaRouter;
 
         // We now tell the activity manager it is okay to run third party
         // code.  It will call back into us once it has gotten to the state
@@ -1063,6 +1076,12 @@
                 } catch (Throwable e) {
                     reportWtf("Notifying PrintManagerService running", e);
                 }
+
+                try {
+                    if (mediaRouterF != null) mediaRouterF.systemRunning();
+                } catch (Throwable e) {
+                    reportWtf("Notifying MediaRouterService running", e);
+                }
             }
         });
 
diff --git a/services/java/com/android/server/am/ActiveServices.java b/services/java/com/android/server/am/ActiveServices.java
index ea0b978a..5476fde 100644
--- a/services/java/com/android/server/am/ActiveServices.java
+++ b/services/java/com/android/server/am/ActiveServices.java
@@ -1187,6 +1187,7 @@
         if (!mRestartingServices.contains(r)) {
             r.createdFromFg = false;
             mRestartingServices.add(r);
+            r.makeRestarting(mAm.mProcessStats.getMemFactorLocked(), now);
         }
 
         r.cancelNotification();
@@ -1220,6 +1221,9 @@
         if (removed || callingUid != r.appInfo.uid) {
             r.resetRestartCounter();
         }
+        if (removed) {
+            r.clearRestarting(mAm.mProcessStats.getMemFactorLocked(), SystemClock.uptimeMillis());
+        }
         mAm.mHandler.removeCallbacks(r.restarter);
         return true;
     }
@@ -1243,7 +1247,9 @@
 
         // We are now bringing the service up, so no longer in the
         // restarting state.
-        mRestartingServices.remove(r);
+        if (mRestartingServices.remove(r)) {
+            r.clearRestarting(mAm.mProcessStats.getMemFactorLocked(), SystemClock.uptimeMillis());
+        }
 
         // Make sure this service is no longer considered delayed, we are starting it now.
         if (r.delayed) {
@@ -1581,6 +1587,7 @@
             }
             r.app.services.remove(r);
             if (r.app.thread != null) {
+                updateServiceForegroundLocked(r.app, false);
                 try {
                     bumpServiceExecutingLocked(r, false, "destroy");
                     mDestroyingServices.add(r);
@@ -1591,7 +1598,6 @@
                             + r.shortName, e);
                     serviceProcessGoneLocked(r);
                 }
-                updateServiceForegroundLocked(r.app, false);
             } else {
                 if (DEBUG_SERVICE) Slog.v(
                     TAG, "Removed service that has no process: " + r);
@@ -1816,6 +1822,9 @@
                     r.tracker = null;
                 }
             }
+            if (finishing) {
+                r.app = null;
+            }
         }
     }
 
@@ -1960,8 +1969,7 @@
         }
     }
 
-    final void killServicesLocked(ProcessRecord app,
-            boolean allowRestart) {
+    final void killServicesLocked(ProcessRecord app, boolean allowRestart) {
         // Report disconnected services.
         if (false) {
             // XXX we are letting the client link to the service for
@@ -1990,16 +1998,8 @@
             }
         }
 
-        // Clean up any connections this application has to other services.
-        for (int i=app.connections.size()-1; i>=0; i--) {
-            ConnectionRecord r = app.connections.valueAt(i);
-            removeConnectionLocked(r, app, null);
-        }
-        app.connections.clear();
-
+        // First clear app state from services.
         for (int i=app.services.size()-1; i>=0; i--) {
-            // Any services running in the application need to be placed
-            // back in the pending list.
             ServiceRecord sr = app.services.valueAt(i);
             synchronized (sr.stats.getBatteryStats()) {
                 sr.stats.stopLaunchedLocked();
@@ -2020,8 +2020,21 @@
                 b.binder = null;
                 b.requested = b.received = b.hasBound = false;
             }
+        }
 
-            if (sr.crashCount >= 2 && (sr.serviceInfo.applicationInfo.flags
+        // Clean up any connections this application has to other services.
+        for (int i=app.connections.size()-1; i>=0; i--) {
+            ConnectionRecord r = app.connections.valueAt(i);
+            removeConnectionLocked(r, app, null);
+        }
+        app.connections.clear();
+
+        // Now do remaining service cleanup.
+        for (int i=app.services.size()-1; i>=0; i--) {
+            // Any services running in the application may need to be placed
+            // back in the pending list.
+            ServiceRecord sr = app.services.valueAt(i);
+            if (allowRestart && sr.crashCount >= 2 && (sr.serviceInfo.applicationInfo.flags
                     &ApplicationInfo.FLAG_PERSISTENT) == 0) {
                 Slog.w(TAG, "Service crashed " + sr.crashCount
                         + " times, stopping: " + sr);
@@ -2054,6 +2067,17 @@
 
         if (!allowRestart) {
             app.services.clear();
+
+            // Make sure there are no more restarting services for this process.
+            for (int i=mRestartingServices.size()-1; i>=0; i--) {
+                ServiceRecord r = mRestartingServices.get(i);
+                if (r.processName.equals(app.processName) &&
+                        r.serviceInfo.applicationInfo.uid == app.info.uid) {
+                    mRestartingServices.remove(i);
+                    r.clearRestarting(mAm.mProcessStats.getMemFactorLocked(),
+                            SystemClock.uptimeMillis());
+                }
+            }
         }
 
         // Make sure we have no more records on the stopping list.
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index a193022..253b6b3 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -11905,6 +11905,7 @@
         boolean dumpDalvik = false;
         boolean oomOnly = false;
         boolean isCompact = false;
+        boolean localOnly = false;
         
         int opti = 0;
         while (opti < args.length) {
@@ -11923,12 +11924,15 @@
                 isCompact = true;
             } else if ("--oom".equals(opt)) {
                 oomOnly = true;
+            } else if ("--local".equals(opt)) {
+                localOnly = true;
             } else if ("-h".equals(opt)) {
                 pw.println("meminfo dump options: [-a] [-d] [-c] [--oom] [process]");
                 pw.println("  -a: include all available information for each process.");
                 pw.println("  -d: include dalvik details when dumping process details.");
                 pw.println("  -c: dump in a compact machine-parseable representation.");
                 pw.println("  --oom: only show processes organized by oom adj.");
+                pw.println("  --local: only collect details locally, don't call process.");
                 pw.println("If [process] is specified it can be the name or ");
                 pw.println("pid of a specific process to dump.");
                 return;
@@ -12045,14 +12049,22 @@
                     mi.dalvikPrivateDirty = (int)tmpLong[0];
                 }
                 if (dumpDetails) {
-                    try {
-                        pw.flush();
-                        thread.dumpMemInfo(fd, mi, isCheckinRequest, dumpFullDetails,
-                                dumpDalvik, innerArgs);
-                    } catch (RemoteException e) {
-                        if (!isCheckinRequest) {
-                            pw.println("Got RemoteException!");
+                    if (localOnly) {
+                        ActivityThread.dumpMemInfoTable(pw, mi, isCheckinRequest, dumpFullDetails,
+                                dumpDalvik, pid, r.processName, 0, 0, 0, 0, 0, 0);
+                        if (isCheckinRequest) {
+                            pw.println();
+                        }
+                    } else {
+                        try {
                             pw.flush();
+                            thread.dumpMemInfo(fd, mi, isCheckinRequest, dumpFullDetails,
+                                    dumpDalvik, innerArgs);
+                        } catch (RemoteException e) {
+                            if (!isCheckinRequest) {
+                                pw.println("Got RemoteException!");
+                                pw.flush();
+                            }
                         }
                     }
                 }
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index 489a0e9..a459622 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -36,7 +36,6 @@
 import static com.android.server.am.ActivityStackSupervisor.DEBUG_STATES;
 import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID;
 
-import android.os.Trace;
 import com.android.internal.os.BatteryStatsImpl;
 import com.android.internal.util.Objects;
 import com.android.server.Watchdog;
@@ -64,12 +63,14 @@
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Bundle;
+import android.os.Debug;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
 import android.os.RemoteException;
 import android.os.SystemClock;
+import android.os.Trace;
 import android.os.UserHandle;
 import android.util.EventLog;
 import android.util.Slog;
@@ -1126,7 +1127,7 @@
                     } else if (isActivityOverHome(r)) {
                         if (DEBUG_VISBILITY) Slog.v(TAG, "Showing home: at " + r);
                         showHomeBehindStack = true;
-                        behindFullscreen = true;
+                        behindFullscreen = !isHomeStack();
                     }
                 } else {
                     if (DEBUG_VISBILITY) Slog.v(
@@ -1924,26 +1925,38 @@
                 // bottom of the activity stack.  This also keeps it
                 // correctly ordered with any activities we previously
                 // moved.
+                final ThumbnailHolder newThumbHolder;
+                final TaskRecord targetTask;
                 final ActivityRecord bottom =
                         !mTaskHistory.isEmpty() && !mTaskHistory.get(0).mActivities.isEmpty() ?
-                        mTaskHistory.get(0).mActivities.get(0) : null;
+                                mTaskHistory.get(0).mActivities.get(0) : null;
                 if (bottom != null && target.taskAffinity != null
                         && target.taskAffinity.equals(bottom.task.affinity)) {
                     // If the activity currently at the bottom has the
                     // same task affinity as the one we are moving,
                     // then merge it into the same task.
-                    target.setTask(bottom.task, bottom.thumbHolder, false);
+                    targetTask = bottom.task;
+                    newThumbHolder = bottom.thumbHolder == null ? targetTask : bottom.thumbHolder;
                     if (DEBUG_TASKS) Slog.v(TAG, "Start pushing activity " + target
                             + " out to bottom task " + bottom.task);
                 } else {
-                    target.setTask(createTaskRecord(mStackSupervisor.getNextTaskId(), target.info,
-                            null, false), null, false);
-                    target.task.affinityIntent = target.intent;
+                    targetTask = createTaskRecord(mStackSupervisor.getNextTaskId(), target.info,
+                            null, false);
+                    newThumbHolder = targetTask;
+                    targetTask.affinityIntent = target.intent;
                     if (DEBUG_TASKS) Slog.v(TAG, "Start pushing activity " + target
                             + " out to new task " + target.task);
                 }
 
-                final TaskRecord targetTask = target.task;
+                if (clearWhenTaskReset) {
+                    // This is the start of a new sub-task.
+                    if (target.thumbHolder == null) {
+                        target.thumbHolder = new ThumbnailHolder();
+                    }
+                } else {
+                    target.thumbHolder = newThumbHolder;
+                }
+
                 final int targetTaskId = targetTask.taskId;
                 mWindowManager.setAppGroupId(target.appToken, targetTaskId);
 
@@ -1964,8 +1977,8 @@
                         }
                     }
                     if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Removing activity " + p + " from task="
-                            + task + " adding to task=" + targetTask,
-                            new RuntimeException("here").fillInStackTrace());
+                            + task + " adding to task=" + targetTask
+                            + " Callers=" + Debug.getCallers(4));
                     if (DEBUG_TASKS) Slog.v(TAG, "Pushing next activity " + p
                             + " out to target's task " + target.task);
                     p.setTask(targetTask, curThumbHolder, false);
diff --git a/services/java/com/android/server/am/BatteryStatsService.java b/services/java/com/android/server/am/BatteryStatsService.java
index 0dd950e..2d59678 100644
--- a/services/java/com/android/server/am/BatteryStatsService.java
+++ b/services/java/com/android/server/am/BatteryStatsService.java
@@ -419,6 +419,20 @@
         }
     }
 
+    public void noteWifiBatchedScanStartedFromSource(WorkSource ws, int csph) {
+        enforceCallingPermission();
+        synchronized (mStats) {
+            mStats.noteWifiBatchedScanStartedFromSourceLocked(ws, csph);
+        }
+    }
+
+    public void noteWifiBatchedScanStoppedFromSource(WorkSource ws) {
+        enforceCallingPermission();
+        synchronized (mStats) {
+            mStats.noteWifiBatchedScanStoppedFromSourceLocked(ws);
+        }
+    }
+
     public void noteWifiMulticastEnabledFromSource(WorkSource ws) {
         enforceCallingPermission();
         synchronized (mStats) {
diff --git a/services/java/com/android/server/am/ConnectionRecord.java b/services/java/com/android/server/am/ConnectionRecord.java
index 576adc2..423e540 100644
--- a/services/java/com/android/server/am/ConnectionRecord.java
+++ b/services/java/com/android/server/am/ConnectionRecord.java
@@ -27,7 +27,7 @@
  */
 final class ConnectionRecord {
     final AppBindRecord binding;    // The application/service binding.
-    final ActivityRecord activity;   // If non-null, the owning activity.
+    final ActivityRecord activity;  // If non-null, the owning activity.
     final IServiceConnection conn;  // The client connection.
     final int flags;                // Binding options.
     final int clientLabel;          // String resource labeling this client.
diff --git a/services/java/com/android/server/am/ProcessStatsService.java b/services/java/com/android/server/am/ProcessStatsService.java
index 8d16880..e05fcda 100644
--- a/services/java/com/android/server/am/ProcessStatsService.java
+++ b/services/java/com/android/server/am/ProcessStatsService.java
@@ -750,23 +750,12 @@
                     return;
                 } else {
                     // Not an option, last argument must be a package name.
-                    try {
-                        IPackageManager pm = AppGlobals.getPackageManager();
-                        if (pm.getPackageUid(arg, UserHandle.getCallingUserId()) >= 0) {
-                            reqPackage = arg;
-                            // Include all details, since we know we are only going to
-                            // be dumping a smaller set of data.  In fact only the details
-                            // container per-package data, so that are needed to be able
-                            // to dump anything at all when filtering by package.
-                            dumpDetails = true;
-                        }
-                    } catch (RemoteException e) {
-                    }
-                    if (reqPackage == null) {
-                        pw.println("Unknown package: " + arg);
-                        dumpHelp(pw);
-                        return;
-                    }
+                    reqPackage = arg;
+                    // Include all details, since we know we are only going to
+                    // be dumping a smaller set of data.  In fact only the details
+                    // container per-package data, so that are needed to be able
+                    // to dump anything at all when filtering by package.
+                    dumpDetails = true;
                 }
             }
         }
@@ -816,13 +805,14 @@
             }
             return;
         } else if (aggregateHours != 0) {
+            pw.print("AGGREGATED OVER LAST "); pw.print(aggregateHours); pw.println(" HOURS:");
             dumpAggregatedStats(pw, aggregateHours, now, reqPackage, isCompact,
                     dumpDetails, dumpFullDetails, dumpAll, activeOnly);
             return;
         }
 
         boolean sepNeeded = false;
-        if (!currentOnly || isCheckin) {
+        if (dumpAll || isCheckin) {
             mWriteLock.lock();
             try {
                 ArrayList<String> files = getCommittedFiles(0, false, !isCheckin);
@@ -882,11 +872,11 @@
             }
         }
         if (!isCheckin) {
-            if (dumpAll) {
+            if (!currentOnly) {
                 if (sepNeeded) {
                     pw.println();
-                    pw.println("AGGREGATED OVER LAST 24 HOURS:");
                 }
+                pw.println("AGGREGATED OVER LAST 24 HOURS:");
                 dumpAggregatedStats(pw, 24, now, reqPackage, isCompact,
                         dumpDetails, dumpFullDetails, dumpAll, activeOnly);
                 pw.println();
@@ -901,8 +891,8 @@
                 } else {
                     if (sepNeeded) {
                         pw.println();
-                        pw.println("CURRENT STATS:");
                     }
+                    pw.println("CURRENT STATS:");
                     if (dumpDetails || dumpFullDetails) {
                         mProcessStats.dumpLocked(pw, reqPackage, now, !dumpFullDetails, dumpAll,
                                 activeOnly);
diff --git a/services/java/com/android/server/am/ServiceRecord.java b/services/java/com/android/server/am/ServiceRecord.java
index cc1172a..84b1c3a 100644
--- a/services/java/com/android/server/am/ServiceRecord.java
+++ b/services/java/com/android/server/am/ServiceRecord.java
@@ -85,6 +85,7 @@
     ProcessRecord app;      // where this service is running or null.
     ProcessRecord isolatedProc; // keep track of isolated process, if requested
     ProcessStats.ServiceState tracker; // tracking service execution, may be null
+    ProcessStats.ServiceState restartTracker; // tracking service restart
     boolean delayed;        // are we waiting to start this service in the background?
     boolean isForeground;   // is service currently in foreground mode?
     int foregroundId;       // Notification ID of last foreground req.
@@ -340,6 +341,26 @@
         }
     }
 
+    public void makeRestarting(int memFactor, long now) {
+        if (restartTracker == null) {
+            if ((serviceInfo.applicationInfo.flags&ApplicationInfo.FLAG_PERSISTENT) == 0) {
+                restartTracker = ams.mProcessStats.getServiceStateLocked(serviceInfo.packageName,
+                        serviceInfo.applicationInfo.uid, serviceInfo.processName, serviceInfo.name);
+            }
+            if (restartTracker == null) {
+                return;
+            }
+        }
+        restartTracker.setRestarting(true, memFactor, now);
+    }
+
+    public void clearRestarting(int memFactor, long now) {
+        if (restartTracker != null) {
+            restartTracker.setRestarting(false, memFactor, now);
+            restartTracker = null;
+        }
+    }
+
     public AppBindRecord retrieveAppBindingLocked(Intent intent,
             ProcessRecord app) {
         Intent.FilterComparison filter = new Intent.FilterComparison(intent);
diff --git a/services/java/com/android/server/input/InputManagerService.java b/services/java/com/android/server/input/InputManagerService.java
index d749e6c..3145805 100644
--- a/services/java/com/android/server/input/InputManagerService.java
+++ b/services/java/com/android/server/input/InputManagerService.java
@@ -294,6 +294,7 @@
         IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
         filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
         filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+        filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
         filter.addDataScheme("package");
         mContext.registerReceiver(new BroadcastReceiver() {
             @Override
diff --git a/services/java/com/android/server/media/MediaRouterService.java b/services/java/com/android/server/media/MediaRouterService.java
new file mode 100644
index 0000000..2caab40
--- /dev/null
+++ b/services/java/com/android/server/media/MediaRouterService.java
@@ -0,0 +1,1351 @@
+/*
+ * 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.android.server.media;
+
+import com.android.internal.util.Objects;
+import com.android.server.Watchdog;
+
+import android.Manifest;
+import android.app.ActivityManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.media.AudioSystem;
+import android.media.IMediaRouterClient;
+import android.media.IMediaRouterService;
+import android.media.MediaRouter;
+import android.media.MediaRouterClientState;
+import android.media.RemoteDisplayState;
+import android.media.RemoteDisplayState.RemoteDisplayInfo;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.Log;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.util.TimeUtils;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Provides a mechanism for discovering media routes and manages media playback
+ * behalf of applications.
+ * <p>
+ * Currently supports discovering remote displays via remote display provider
+ * services that have been registered by applications.
+ * </p>
+ */
+public final class MediaRouterService extends IMediaRouterService.Stub
+        implements Watchdog.Monitor {
+    private static final String TAG = "MediaRouterService";
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+    /**
+     * Timeout in milliseconds for a selected route to transition from a
+     * disconnected state to a connecting state.  If we don't observe any
+     * progress within this interval, then we will give up and unselect the route.
+     */
+    static final long CONNECTING_TIMEOUT = 5000;
+
+    /**
+     * Timeout in milliseconds for a selected route to transition from a
+     * connecting state to a connected state.  If we don't observe any
+     * progress within this interval, then we will give up and unselect the route.
+     */
+    static final long CONNECTED_TIMEOUT = 60000;
+
+    private final Context mContext;
+
+    // State guarded by mLock.
+    private final Object mLock = new Object();
+    private final SparseArray<UserRecord> mUserRecords = new SparseArray<UserRecord>();
+    private final ArrayMap<IBinder, ClientRecord> mAllClientRecords =
+            new ArrayMap<IBinder, ClientRecord>();
+    private int mCurrentUserId = -1;
+
+    public MediaRouterService(Context context) {
+        mContext = context;
+        Watchdog.getInstance().addMonitor(this);
+    }
+
+    public void systemRunning() {
+        IntentFilter filter = new IntentFilter(Intent.ACTION_USER_SWITCHED);
+        mContext.registerReceiver(new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                if (intent.getAction().equals(Intent.ACTION_USER_SWITCHED)) {
+                    switchUser();
+                }
+            }
+        }, filter);
+
+        switchUser();
+    }
+
+    @Override
+    public void monitor() {
+        synchronized (mLock) { /* check for deadlock */ }
+    }
+
+    // Binder call
+    @Override
+    public void registerClientAsUser(IMediaRouterClient client, String packageName, int userId) {
+        if (client == null) {
+            throw new IllegalArgumentException("client must not be null");
+        }
+
+        final int uid = Binder.getCallingUid();
+        if (!validatePackageName(uid, packageName)) {
+            throw new SecurityException("packageName must match the calling uid");
+        }
+
+        final int pid = Binder.getCallingPid();
+        final int resolvedUserId = ActivityManager.handleIncomingUser(pid, uid, userId,
+                false /*allowAll*/, true /*requireFull*/, "registerClientAsUser", packageName);
+        final long token = Binder.clearCallingIdentity();
+        try {
+            synchronized (mLock) {
+                registerClientLocked(client, pid, packageName, resolvedUserId);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
+    // Binder call
+    @Override
+    public void unregisterClient(IMediaRouterClient client) {
+        if (client == null) {
+            throw new IllegalArgumentException("client must not be null");
+        }
+
+        final long token = Binder.clearCallingIdentity();
+        try {
+            synchronized (mLock) {
+                unregisterClientLocked(client, false);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
+    // Binder call
+    @Override
+    public MediaRouterClientState getState(IMediaRouterClient client) {
+        if (client == null) {
+            throw new IllegalArgumentException("client must not be null");
+        }
+
+        final long token = Binder.clearCallingIdentity();
+        try {
+            synchronized (mLock) {
+                return getStateLocked(client);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
+    // Binder call
+    @Override
+    public void setDiscoveryRequest(IMediaRouterClient client,
+            int routeTypes, boolean activeScan) {
+        if (client == null) {
+            throw new IllegalArgumentException("client must not be null");
+        }
+
+        final long token = Binder.clearCallingIdentity();
+        try {
+            synchronized (mLock) {
+                setDiscoveryRequestLocked(client, routeTypes, activeScan);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
+    // Binder call
+    // A null routeId means that the client wants to unselect its current route.
+    // The explicit flag indicates whether the change was explicitly requested by the
+    // user or the application which may cause changes to propagate out to the rest
+    // of the system.  Should be false when the change is in response to a new globally
+    // selected route or a default selection.
+    @Override
+    public void setSelectedRoute(IMediaRouterClient client, String routeId, boolean explicit) {
+        if (client == null) {
+            throw new IllegalArgumentException("client must not be null");
+        }
+
+        final long token = Binder.clearCallingIdentity();
+        try {
+            synchronized (mLock) {
+                setSelectedRouteLocked(client, routeId, explicit);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
+    // Binder call
+    @Override
+    public void requestSetVolume(IMediaRouterClient client, String routeId, int volume) {
+        if (client == null) {
+            throw new IllegalArgumentException("client must not be null");
+        }
+        if (routeId == null) {
+            throw new IllegalArgumentException("routeId must not be null");
+        }
+
+        final long token = Binder.clearCallingIdentity();
+        try {
+            synchronized (mLock) {
+                requestSetVolumeLocked(client, routeId, volume);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
+    // Binder call
+    @Override
+    public void requestUpdateVolume(IMediaRouterClient client, String routeId, int direction) {
+        if (client == null) {
+            throw new IllegalArgumentException("client must not be null");
+        }
+        if (routeId == null) {
+            throw new IllegalArgumentException("routeId must not be null");
+        }
+
+        final long token = Binder.clearCallingIdentity();
+        try {
+            synchronized (mLock) {
+                requestUpdateVolumeLocked(client, routeId, direction);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
+    // Binder call
+    @Override
+    public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
+        if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP)
+                != PackageManager.PERMISSION_GRANTED) {
+            pw.println("Permission Denial: can't dump MediaRouterService from from pid="
+                    + Binder.getCallingPid()
+                    + ", uid=" + Binder.getCallingUid());
+            return;
+        }
+
+        pw.println("MEDIA ROUTER SERVICE (dumpsys media_router)");
+        pw.println();
+        pw.println("Global state");
+        pw.println("  mCurrentUserId=" + mCurrentUserId);
+
+        synchronized (mLock) {
+            final int count = mUserRecords.size();
+            for (int i = 0; i < count; i++) {
+                UserRecord userRecord = mUserRecords.valueAt(i);
+                pw.println();
+                userRecord.dump(pw, "");
+            }
+        }
+    }
+
+    void switchUser() {
+        synchronized (mLock) {
+            int userId = ActivityManager.getCurrentUser();
+            if (mCurrentUserId != userId) {
+                final int oldUserId = mCurrentUserId;
+                mCurrentUserId = userId; // do this first
+
+                UserRecord oldUser = mUserRecords.get(oldUserId);
+                if (oldUser != null) {
+                    oldUser.mHandler.sendEmptyMessage(UserHandler.MSG_STOP);
+                    disposeUserIfNeededLocked(oldUser); // since no longer current user
+                }
+
+                UserRecord newUser = mUserRecords.get(userId);
+                if (newUser != null) {
+                    newUser.mHandler.sendEmptyMessage(UserHandler.MSG_START);
+                }
+            }
+        }
+    }
+
+    void clientDied(ClientRecord clientRecord) {
+        synchronized (mLock) {
+            unregisterClientLocked(clientRecord.mClient, true);
+        }
+    }
+
+    private void registerClientLocked(IMediaRouterClient client,
+            int pid, String packageName, int userId) {
+        final IBinder binder = client.asBinder();
+        ClientRecord clientRecord = mAllClientRecords.get(binder);
+        if (clientRecord == null) {
+            boolean newUser = false;
+            UserRecord userRecord = mUserRecords.get(userId);
+            if (userRecord == null) {
+                userRecord = new UserRecord(userId);
+                newUser = true;
+            }
+            clientRecord = new ClientRecord(userRecord, client, pid, packageName);
+            try {
+                binder.linkToDeath(clientRecord, 0);
+            } catch (RemoteException ex) {
+                throw new RuntimeException("Media router client died prematurely.", ex);
+            }
+
+            if (newUser) {
+                mUserRecords.put(userId, userRecord);
+                initializeUserLocked(userRecord);
+            }
+
+            userRecord.mClientRecords.add(clientRecord);
+            mAllClientRecords.put(binder, clientRecord);
+            initializeClientLocked(clientRecord);
+        }
+    }
+
+    private void unregisterClientLocked(IMediaRouterClient client, boolean died) {
+        ClientRecord clientRecord = mAllClientRecords.remove(client.asBinder());
+        if (clientRecord != null) {
+            UserRecord userRecord = clientRecord.mUserRecord;
+            userRecord.mClientRecords.remove(clientRecord);
+            disposeClientLocked(clientRecord, died);
+            disposeUserIfNeededLocked(userRecord); // since client removed from user
+        }
+    }
+
+    private MediaRouterClientState getStateLocked(IMediaRouterClient client) {
+        ClientRecord clientRecord = mAllClientRecords.get(client.asBinder());
+        if (clientRecord != null) {
+            return clientRecord.mUserRecord.mState;
+        }
+        return null;
+    }
+
+    private void setDiscoveryRequestLocked(IMediaRouterClient client,
+            int routeTypes, boolean activeScan) {
+        final IBinder binder = client.asBinder();
+        ClientRecord clientRecord = mAllClientRecords.get(binder);
+        if (clientRecord != null) {
+            if (clientRecord.mRouteTypes != routeTypes
+                    || clientRecord.mActiveScan != activeScan) {
+                if (DEBUG) {
+                    Slog.d(TAG, clientRecord + ": Set discovery request, routeTypes=0x"
+                            + Integer.toHexString(routeTypes) + ", activeScan=" + activeScan);
+                }
+                clientRecord.mRouteTypes = routeTypes;
+                clientRecord.mActiveScan = activeScan;
+                clientRecord.mUserRecord.mHandler.sendEmptyMessage(
+                        UserHandler.MSG_UPDATE_DISCOVERY_REQUEST);
+            }
+        }
+    }
+
+    private void setSelectedRouteLocked(IMediaRouterClient client,
+            String routeId, boolean explicit) {
+        ClientRecord clientRecord = mAllClientRecords.get(client.asBinder());
+        if (clientRecord != null) {
+            final String oldRouteId = clientRecord.mSelectedRouteId;
+            if (!Objects.equal(routeId, oldRouteId)) {
+                if (DEBUG) {
+                    Slog.d(TAG, clientRecord + ": Set selected route, routeId=" + routeId
+                            + ", oldRouteId=" + oldRouteId
+                            + ", explicit=" + explicit);
+                }
+
+                clientRecord.mSelectedRouteId = routeId;
+                if (explicit) {
+                    if (oldRouteId != null) {
+                        clientRecord.mUserRecord.mHandler.obtainMessage(
+                                UserHandler.MSG_UNSELECT_ROUTE, oldRouteId).sendToTarget();
+                    }
+                    if (routeId != null) {
+                        clientRecord.mUserRecord.mHandler.obtainMessage(
+                                UserHandler.MSG_SELECT_ROUTE, routeId).sendToTarget();
+                    }
+                }
+            }
+        }
+    }
+
+    private void requestSetVolumeLocked(IMediaRouterClient client,
+            String routeId, int volume) {
+        final IBinder binder = client.asBinder();
+        ClientRecord clientRecord = mAllClientRecords.get(binder);
+        if (clientRecord != null) {
+            clientRecord.mUserRecord.mHandler.obtainMessage(
+                    UserHandler.MSG_REQUEST_SET_VOLUME, volume, 0, routeId).sendToTarget();
+        }
+    }
+
+    private void requestUpdateVolumeLocked(IMediaRouterClient client,
+            String routeId, int direction) {
+        final IBinder binder = client.asBinder();
+        ClientRecord clientRecord = mAllClientRecords.get(binder);
+        if (clientRecord != null) {
+            clientRecord.mUserRecord.mHandler.obtainMessage(
+                    UserHandler.MSG_REQUEST_UPDATE_VOLUME, direction, 0, routeId).sendToTarget();
+        }
+    }
+
+    private void initializeUserLocked(UserRecord userRecord) {
+        if (DEBUG) {
+            Slog.d(TAG, userRecord + ": Initialized");
+        }
+        if (userRecord.mUserId == mCurrentUserId) {
+            userRecord.mHandler.sendEmptyMessage(UserHandler.MSG_START);
+        }
+    }
+
+    private void disposeUserIfNeededLocked(UserRecord userRecord) {
+        // If there are no records left and the user is no longer current then go ahead
+        // and purge the user record and all of its associated state.  If the user is current
+        // then leave it alone since we might be connected to a route or want to query
+        // the same route information again soon.
+        if (userRecord.mUserId != mCurrentUserId
+                && userRecord.mClientRecords.isEmpty()) {
+            if (DEBUG) {
+                Slog.d(TAG, userRecord + ": Disposed");
+            }
+            mUserRecords.remove(userRecord.mUserId);
+            // Note: User already stopped (by switchUser) so no need to send stop message here.
+        }
+    }
+
+    private void initializeClientLocked(ClientRecord clientRecord) {
+        if (DEBUG) {
+            Slog.d(TAG, clientRecord + ": Registered");
+        }
+    }
+
+    private void disposeClientLocked(ClientRecord clientRecord, boolean died) {
+        if (DEBUG) {
+            if (died) {
+                Slog.d(TAG, clientRecord + ": Died!");
+            } else {
+                Slog.d(TAG, clientRecord + ": Unregistered");
+            }
+        }
+        if (clientRecord.mRouteTypes != 0 || clientRecord.mActiveScan) {
+            clientRecord.mUserRecord.mHandler.sendEmptyMessage(
+                    UserHandler.MSG_UPDATE_DISCOVERY_REQUEST);
+        }
+        clientRecord.dispose();
+    }
+
+    private boolean validatePackageName(int uid, String packageName) {
+        if (packageName != null) {
+            String[] packageNames = mContext.getPackageManager().getPackagesForUid(uid);
+            if (packageNames != null) {
+                for (String n : packageNames) {
+                    if (n.equals(packageName)) {
+                        return true;
+                    }
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Information about a particular client of the media router.
+     * The contents of this object is guarded by mLock.
+     */
+    final class ClientRecord implements DeathRecipient {
+        public final UserRecord mUserRecord;
+        public final IMediaRouterClient mClient;
+        public final int mPid;
+        public final String mPackageName;
+
+        public int mRouteTypes;
+        public boolean mActiveScan;
+        public String mSelectedRouteId;
+
+        public ClientRecord(UserRecord userRecord, IMediaRouterClient client,
+                int pid, String packageName) {
+            mUserRecord = userRecord;
+            mClient = client;
+            mPid = pid;
+            mPackageName = packageName;
+        }
+
+        public void dispose() {
+            mClient.asBinder().unlinkToDeath(this, 0);
+        }
+
+        @Override
+        public void binderDied() {
+            clientDied(this);
+        }
+
+        public void dump(PrintWriter pw, String prefix) {
+            pw.println(prefix + this);
+
+            final String indent = prefix + "  ";
+            pw.println(indent + "mRouteTypes=0x" + Integer.toHexString(mRouteTypes));
+            pw.println(indent + "mActiveScan=" + mActiveScan);
+            pw.println(indent + "mSelectedRouteId=" + mSelectedRouteId);
+        }
+
+        @Override
+        public String toString() {
+            return "Client " + mPackageName + " (pid " + mPid + ")";
+        }
+    }
+
+    /**
+     * Information about a particular user.
+     * The contents of this object is guarded by mLock.
+     */
+    final class UserRecord {
+        public final int mUserId;
+        public final ArrayList<ClientRecord> mClientRecords = new ArrayList<ClientRecord>();
+        public final UserHandler mHandler;
+        public MediaRouterClientState mState;
+
+        public UserRecord(int userId) {
+            mUserId = userId;
+            mHandler = new UserHandler(MediaRouterService.this, this);
+        }
+
+        public void dump(final PrintWriter pw, String prefix) {
+            pw.println(prefix + this);
+
+            final String indent = prefix + "  ";
+            final int clientCount = mClientRecords.size();
+            if (clientCount != 0) {
+                for (int i = 0; i < clientCount; i++) {
+                    mClientRecords.get(i).dump(pw, indent);
+                }
+            } else {
+                pw.println(indent + "<no clients>");
+            }
+
+            if (!mHandler.runWithScissors(new Runnable() {
+                @Override
+                public void run() {
+                    mHandler.dump(pw, indent);
+                }
+            }, 1000)) {
+                pw.println(indent + "<could not dump handler state>");
+            }
+         }
+
+        @Override
+        public String toString() {
+            return "User " + mUserId;
+        }
+    }
+
+    /**
+     * Media router handler
+     * <p>
+     * Since remote display providers are designed to be single-threaded by nature,
+     * this class encapsulates all of the associated functionality and exports state
+     * to the service as it evolves.
+     * </p><p>
+     * One important task of this class is to keep track of the current globally selected
+     * route id for certain routes that have global effects, such as remote displays.
+     * Global route selections override local selections made within apps.  The change
+     * is propagated to all apps so that they are all in sync.  Synchronization works
+     * both ways.  Whenever the globally selected route is explicitly unselected by any
+     * app, then it becomes unselected globally and all apps are informed.
+     * </p><p>
+     * This class is currently hardcoded to work with remote display providers but
+     * it is intended to be eventually extended to support more general route providers
+     * similar to the support library media router.
+     * </p>
+     */
+    static final class UserHandler extends Handler
+            implements RemoteDisplayProviderWatcher.Callback,
+            RemoteDisplayProviderProxy.Callback {
+        public static final int MSG_START = 1;
+        public static final int MSG_STOP = 2;
+        public static final int MSG_UPDATE_DISCOVERY_REQUEST = 3;
+        public static final int MSG_SELECT_ROUTE = 4;
+        public static final int MSG_UNSELECT_ROUTE = 5;
+        public static final int MSG_REQUEST_SET_VOLUME = 6;
+        public static final int MSG_REQUEST_UPDATE_VOLUME = 7;
+        private static final int MSG_UPDATE_CLIENT_STATE = 8;
+        private static final int MSG_CONNECTION_TIMED_OUT = 9;
+
+        private static final int TIMEOUT_REASON_NOT_AVAILABLE = 1;
+        private static final int TIMEOUT_REASON_WAITING_FOR_CONNECTING = 2;
+        private static final int TIMEOUT_REASON_WAITING_FOR_CONNECTED = 3;
+
+        private final MediaRouterService mService;
+        private final UserRecord mUserRecord;
+        private final RemoteDisplayProviderWatcher mWatcher;
+        private final ArrayList<ProviderRecord> mProviderRecords =
+                new ArrayList<ProviderRecord>();
+        private final ArrayList<IMediaRouterClient> mTempClients =
+                new ArrayList<IMediaRouterClient>();
+
+        private boolean mRunning;
+        private int mDiscoveryMode = RemoteDisplayState.DISCOVERY_MODE_NONE;
+        private RouteRecord mGloballySelectedRouteRecord;
+        private int mConnectionTimeoutReason;
+        private long mConnectionTimeoutStartTime;
+        private boolean mClientStateUpdateScheduled;
+
+        public UserHandler(MediaRouterService service, UserRecord userRecord) {
+            super(Looper.getMainLooper(), null, true);
+            mService = service;
+            mUserRecord = userRecord;
+            mWatcher = new RemoteDisplayProviderWatcher(service.mContext, this,
+                    this, mUserRecord.mUserId);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_START: {
+                    start();
+                    break;
+                }
+                case MSG_STOP: {
+                    stop();
+                    break;
+                }
+                case MSG_UPDATE_DISCOVERY_REQUEST: {
+                    updateDiscoveryRequest();
+                    break;
+                }
+                case MSG_SELECT_ROUTE: {
+                    selectRoute((String)msg.obj);
+                    break;
+                }
+                case MSG_UNSELECT_ROUTE: {
+                    unselectRoute((String)msg.obj);
+                    break;
+                }
+                case MSG_REQUEST_SET_VOLUME: {
+                    requestSetVolume((String)msg.obj, msg.arg1);
+                    break;
+                }
+                case MSG_REQUEST_UPDATE_VOLUME: {
+                    requestUpdateVolume((String)msg.obj, msg.arg1);
+                    break;
+                }
+                case MSG_UPDATE_CLIENT_STATE: {
+                    updateClientState();
+                    break;
+                }
+                case MSG_CONNECTION_TIMED_OUT: {
+                    connectionTimedOut();
+                    break;
+                }
+            }
+        }
+
+        public void dump(PrintWriter pw, String prefix) {
+            pw.println(prefix + "Handler");
+
+            final String indent = prefix + "  ";
+            pw.println(indent + "mRunning=" + mRunning);
+            pw.println(indent + "mDiscoveryMode=" + mDiscoveryMode);
+            pw.println(indent + "mGloballySelectedRouteRecord=" + mGloballySelectedRouteRecord);
+            pw.println(indent + "mConnectionTimeoutReason=" + mConnectionTimeoutReason);
+            pw.println(indent + "mConnectionTimeoutStartTime=" + (mConnectionTimeoutReason != 0 ?
+                    TimeUtils.formatUptime(mConnectionTimeoutStartTime) : "<n/a>"));
+
+            mWatcher.dump(pw, prefix);
+
+            final int providerCount = mProviderRecords.size();
+            if (providerCount != 0) {
+                for (int i = 0; i < providerCount; i++) {
+                    mProviderRecords.get(i).dump(pw, prefix);
+                }
+            } else {
+                pw.println(indent + "<no providers>");
+            }
+        }
+
+        private void start() {
+            if (!mRunning) {
+                mRunning = true;
+                mWatcher.start(); // also starts all providers
+            }
+        }
+
+        private void stop() {
+            if (mRunning) {
+                mRunning = false;
+                unselectGloballySelectedRoute();
+                mWatcher.stop(); // also stops all providers
+            }
+        }
+
+        private void updateDiscoveryRequest() {
+            int routeTypes = 0;
+            boolean activeScan = false;
+            synchronized (mService.mLock) {
+                final int count = mUserRecord.mClientRecords.size();
+                for (int i = 0; i < count; i++) {
+                    ClientRecord clientRecord = mUserRecord.mClientRecords.get(i);
+                    routeTypes |= clientRecord.mRouteTypes;
+                    activeScan |= clientRecord.mActiveScan;
+                }
+            }
+
+            final int newDiscoveryMode;
+            if ((routeTypes & (MediaRouter.ROUTE_TYPE_LIVE_VIDEO
+                    | MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY)) != 0) {
+                if (activeScan) {
+                    newDiscoveryMode = RemoteDisplayState.DISCOVERY_MODE_ACTIVE;
+                } else {
+                    newDiscoveryMode = RemoteDisplayState.DISCOVERY_MODE_PASSIVE;
+                }
+            } else {
+                newDiscoveryMode = RemoteDisplayState.DISCOVERY_MODE_NONE;
+            }
+
+            if (mDiscoveryMode != newDiscoveryMode) {
+                mDiscoveryMode = newDiscoveryMode;
+                final int count = mProviderRecords.size();
+                for (int i = 0; i < count; i++) {
+                    mProviderRecords.get(i).getProvider().setDiscoveryMode(mDiscoveryMode);
+                }
+            }
+        }
+
+        private void selectRoute(String routeId) {
+            if (routeId != null
+                    && (mGloballySelectedRouteRecord == null
+                            || !routeId.equals(mGloballySelectedRouteRecord.getUniqueId()))) {
+                RouteRecord routeRecord = findRouteRecord(routeId);
+                if (routeRecord != null) {
+                    unselectGloballySelectedRoute();
+
+                    Slog.i(TAG, "Selected global route:" + routeRecord);
+                    mGloballySelectedRouteRecord = routeRecord;
+                    checkGloballySelectedRouteState();
+                    routeRecord.getProvider().setSelectedDisplay(routeRecord.getDescriptorId());
+
+                    scheduleUpdateClientState();
+                }
+            }
+        }
+
+        private void unselectRoute(String routeId) {
+            if (routeId != null
+                    && mGloballySelectedRouteRecord != null
+                    && routeId.equals(mGloballySelectedRouteRecord.getUniqueId())) {
+                unselectGloballySelectedRoute();
+            }
+        }
+
+        private void unselectGloballySelectedRoute() {
+            if (mGloballySelectedRouteRecord != null) {
+                Slog.i(TAG, "Unselected global route:" + mGloballySelectedRouteRecord);
+                mGloballySelectedRouteRecord.getProvider().setSelectedDisplay(null);
+                mGloballySelectedRouteRecord = null;
+                checkGloballySelectedRouteState();
+
+                scheduleUpdateClientState();
+            }
+        }
+
+        private void requestSetVolume(String routeId, int volume) {
+            if (mGloballySelectedRouteRecord != null
+                    && routeId.equals(mGloballySelectedRouteRecord.getUniqueId())) {
+                mGloballySelectedRouteRecord.getProvider().setDisplayVolume(volume);
+            }
+        }
+
+        private void requestUpdateVolume(String routeId, int direction) {
+            if (mGloballySelectedRouteRecord != null
+                    && routeId.equals(mGloballySelectedRouteRecord.getUniqueId())) {
+                mGloballySelectedRouteRecord.getProvider().adjustDisplayVolume(direction);
+            }
+        }
+
+        @Override
+        public void addProvider(RemoteDisplayProviderProxy provider) {
+            provider.setCallback(this);
+            provider.setDiscoveryMode(mDiscoveryMode);
+            provider.setSelectedDisplay(null); // just to be safe
+
+            ProviderRecord providerRecord = new ProviderRecord(provider);
+            mProviderRecords.add(providerRecord);
+            providerRecord.updateDescriptor(provider.getDisplayState());
+
+            scheduleUpdateClientState();
+        }
+
+        @Override
+        public void removeProvider(RemoteDisplayProviderProxy provider) {
+            int index = findProviderRecord(provider);
+            if (index >= 0) {
+                ProviderRecord providerRecord = mProviderRecords.remove(index);
+                providerRecord.updateDescriptor(null); // mark routes invalid
+                provider.setCallback(null);
+                provider.setDiscoveryMode(RemoteDisplayState.DISCOVERY_MODE_NONE);
+
+                checkGloballySelectedRouteState();
+                scheduleUpdateClientState();
+            }
+        }
+
+        @Override
+        public void onDisplayStateChanged(RemoteDisplayProviderProxy provider,
+                RemoteDisplayState state) {
+            updateProvider(provider, state);
+        }
+
+        private void updateProvider(RemoteDisplayProviderProxy provider,
+                RemoteDisplayState state) {
+            int index = findProviderRecord(provider);
+            if (index >= 0) {
+                ProviderRecord providerRecord = mProviderRecords.get(index);
+                if (providerRecord.updateDescriptor(state)) {
+                    checkGloballySelectedRouteState();
+                    scheduleUpdateClientState();
+                }
+            }
+        }
+
+        /**
+         * This function is called whenever the state of the globally selected route
+         * may have changed.  It checks the state and updates timeouts or unselects
+         * the route as appropriate.
+         */
+        private void checkGloballySelectedRouteState() {
+            // Unschedule timeouts when the route is unselected.
+            if (mGloballySelectedRouteRecord == null) {
+                updateConnectionTimeout(0);
+                return;
+            }
+
+            // Ensure that the route is still present and enabled.
+            if (!mGloballySelectedRouteRecord.isValid()
+                    || !mGloballySelectedRouteRecord.isEnabled()) {
+                updateConnectionTimeout(TIMEOUT_REASON_NOT_AVAILABLE);
+                return;
+            }
+
+            // Check the route status.
+            switch (mGloballySelectedRouteRecord.getStatus()) {
+                case MediaRouter.RouteInfo.STATUS_NONE:
+                case MediaRouter.RouteInfo.STATUS_CONNECTED:
+                    if (mConnectionTimeoutReason != 0) {
+                        Slog.i(TAG, "Connected to global route: "
+                                + mGloballySelectedRouteRecord);
+                    }
+                    updateConnectionTimeout(0);
+                    break;
+                case MediaRouter.RouteInfo.STATUS_CONNECTING:
+                    if (mConnectionTimeoutReason != 0) {
+                        Slog.i(TAG, "Connecting to global route: "
+                                + mGloballySelectedRouteRecord);
+                    }
+                    updateConnectionTimeout(TIMEOUT_REASON_WAITING_FOR_CONNECTED);
+                    break;
+                case MediaRouter.RouteInfo.STATUS_SCANNING:
+                case MediaRouter.RouteInfo.STATUS_AVAILABLE:
+                    updateConnectionTimeout(TIMEOUT_REASON_WAITING_FOR_CONNECTING);
+                    break;
+                case MediaRouter.RouteInfo.STATUS_NOT_AVAILABLE:
+                case MediaRouter.RouteInfo.STATUS_IN_USE:
+                default:
+                    updateConnectionTimeout(TIMEOUT_REASON_NOT_AVAILABLE);
+                    break;
+            }
+        }
+
+        private void updateConnectionTimeout(int reason) {
+            if (reason != mConnectionTimeoutReason) {
+                if (mConnectionTimeoutReason != 0) {
+                    removeMessages(MSG_CONNECTION_TIMED_OUT);
+                }
+                mConnectionTimeoutReason = reason;
+                mConnectionTimeoutStartTime = SystemClock.uptimeMillis();
+                switch (reason) {
+                    case TIMEOUT_REASON_NOT_AVAILABLE:
+                        // Route became unavailable.  Unselect it immediately.
+                        sendEmptyMessage(MSG_CONNECTION_TIMED_OUT);
+                        break;
+                    case TIMEOUT_REASON_WAITING_FOR_CONNECTING:
+                        // Waiting for route to start connecting.
+                        sendEmptyMessageDelayed(MSG_CONNECTION_TIMED_OUT, CONNECTING_TIMEOUT);
+                        break;
+                    case TIMEOUT_REASON_WAITING_FOR_CONNECTED:
+                        // Waiting for route to complete connection.
+                        sendEmptyMessageDelayed(MSG_CONNECTION_TIMED_OUT, CONNECTED_TIMEOUT);
+                        break;
+                }
+            }
+        }
+
+        private void connectionTimedOut() {
+            if (mConnectionTimeoutReason == 0 || mGloballySelectedRouteRecord == null) {
+                // Shouldn't get here.  There must be a bug somewhere.
+                Log.wtf(TAG, "Handled connection timeout for no reason.");
+                return;
+            }
+
+            switch (mConnectionTimeoutReason) {
+                case TIMEOUT_REASON_NOT_AVAILABLE:
+                    Slog.i(TAG, "Global route no longer available: "
+                            + mGloballySelectedRouteRecord);
+                    break;
+                case TIMEOUT_REASON_WAITING_FOR_CONNECTING:
+                    Slog.i(TAG, "Global route timed out while waiting for "
+                            + "connection attempt to begin after "
+                            + (SystemClock.uptimeMillis() - mConnectionTimeoutStartTime)
+                            + " ms: " + mGloballySelectedRouteRecord);
+                    break;
+                case TIMEOUT_REASON_WAITING_FOR_CONNECTED:
+                    Slog.i(TAG, "Global route timed out while connecting after "
+                            + (SystemClock.uptimeMillis() - mConnectionTimeoutStartTime)
+                            + " ms: " + mGloballySelectedRouteRecord);
+                    break;
+            }
+            mConnectionTimeoutReason = 0;
+
+            unselectGloballySelectedRoute();
+        }
+
+        private void scheduleUpdateClientState() {
+            if (!mClientStateUpdateScheduled) {
+                mClientStateUpdateScheduled = true;
+                sendEmptyMessage(MSG_UPDATE_CLIENT_STATE);
+            }
+        }
+
+        private void updateClientState() {
+            mClientStateUpdateScheduled = false;
+
+            // Build a new client state.
+            MediaRouterClientState state = new MediaRouterClientState();
+            state.globallySelectedRouteId = mGloballySelectedRouteRecord != null ?
+                    mGloballySelectedRouteRecord.getUniqueId() : null;
+            final int providerCount = mProviderRecords.size();
+            for (int i = 0; i < providerCount; i++) {
+                mProviderRecords.get(i).appendClientState(state);
+            }
+
+            try {
+                synchronized (mService.mLock) {
+                    // Update the UserRecord.
+                    mUserRecord.mState = state;
+
+                    // Collect all clients.
+                    final int count = mUserRecord.mClientRecords.size();
+                    for (int i = 0; i < count; i++) {
+                        mTempClients.add(mUserRecord.mClientRecords.get(i).mClient);
+                    }
+                }
+
+                // Notify all clients (outside of the lock).
+                final int count = mTempClients.size();
+                for (int i = 0; i < count; i++) {
+                    try {
+                        mTempClients.get(i).onStateChanged();
+                    } catch (RemoteException ex) {
+                        // ignore errors, client probably died
+                    }
+                }
+            } finally {
+                // Clear the list in preparation for the next time.
+                mTempClients.clear();
+            }
+        }
+
+        private int findProviderRecord(RemoteDisplayProviderProxy provider) {
+            final int count = mProviderRecords.size();
+            for (int i = 0; i < count; i++) {
+                ProviderRecord record = mProviderRecords.get(i);
+                if (record.getProvider() == provider) {
+                    return i;
+                }
+            }
+            return -1;
+        }
+
+        private RouteRecord findRouteRecord(String uniqueId) {
+            final int count = mProviderRecords.size();
+            for (int i = 0; i < count; i++) {
+                RouteRecord record = mProviderRecords.get(i).findRouteByUniqueId(uniqueId);
+                if (record != null) {
+                    return record;
+                }
+            }
+            return null;
+        }
+
+        static final class ProviderRecord {
+            private final RemoteDisplayProviderProxy mProvider;
+            private final String mUniquePrefix;
+            private final ArrayList<RouteRecord> mRoutes = new ArrayList<RouteRecord>();
+            private RemoteDisplayState mDescriptor;
+
+            public ProviderRecord(RemoteDisplayProviderProxy provider) {
+                mProvider = provider;
+                mUniquePrefix = provider.getFlattenedComponentName() + ":";
+            }
+
+            public RemoteDisplayProviderProxy getProvider() {
+                return mProvider;
+            }
+
+            public String getUniquePrefix() {
+                return mUniquePrefix;
+            }
+
+            public boolean updateDescriptor(RemoteDisplayState descriptor) {
+                boolean changed = false;
+                if (mDescriptor != descriptor) {
+                    mDescriptor = descriptor;
+
+                    // Update all existing routes and reorder them to match
+                    // the order of their descriptors.
+                    int targetIndex = 0;
+                    if (descriptor != null) {
+                        if (descriptor.isValid()) {
+                            final List<RemoteDisplayInfo> routeDescriptors = descriptor.displays;
+                            final int routeCount = routeDescriptors.size();
+                            for (int i = 0; i < routeCount; i++) {
+                                final RemoteDisplayInfo routeDescriptor =
+                                        routeDescriptors.get(i);
+                                final String descriptorId = routeDescriptor.id;
+                                final int sourceIndex = findRouteByDescriptorId(descriptorId);
+                                if (sourceIndex < 0) {
+                                    // Add the route to the provider.
+                                    String uniqueId = assignRouteUniqueId(descriptorId);
+                                    RouteRecord route =
+                                            new RouteRecord(this, descriptorId, uniqueId);
+                                    mRoutes.add(targetIndex++, route);
+                                    route.updateDescriptor(routeDescriptor);
+                                    changed = true;
+                                } else if (sourceIndex < targetIndex) {
+                                    // Ignore route with duplicate id.
+                                    Slog.w(TAG, "Ignoring route descriptor with duplicate id: "
+                                            + routeDescriptor);
+                                } else {
+                                    // Reorder existing route within the list.
+                                    RouteRecord route = mRoutes.get(sourceIndex);
+                                    Collections.swap(mRoutes, sourceIndex, targetIndex++);
+                                    changed |= route.updateDescriptor(routeDescriptor);
+                                }
+                            }
+                        } else {
+                            Slog.w(TAG, "Ignoring invalid descriptor from media route provider: "
+                                    + mProvider.getFlattenedComponentName());
+                        }
+                    }
+
+                    // Dispose all remaining routes that do not have matching descriptors.
+                    for (int i = mRoutes.size() - 1; i >= targetIndex; i--) {
+                        RouteRecord route = mRoutes.remove(i);
+                        route.updateDescriptor(null); // mark route invalid
+                        changed = true;
+                    }
+                }
+                return changed;
+            }
+
+            public void appendClientState(MediaRouterClientState state) {
+                final int routeCount = mRoutes.size();
+                for (int i = 0; i < routeCount; i++) {
+                    state.routes.add(mRoutes.get(i).getInfo());
+                }
+            }
+
+            public RouteRecord findRouteByUniqueId(String uniqueId) {
+                final int routeCount = mRoutes.size();
+                for (int i = 0; i < routeCount; i++) {
+                    RouteRecord route = mRoutes.get(i);
+                    if (route.getUniqueId().equals(uniqueId)) {
+                        return route;
+                    }
+                }
+                return null;
+            }
+
+            private int findRouteByDescriptorId(String descriptorId) {
+                final int routeCount = mRoutes.size();
+                for (int i = 0; i < routeCount; i++) {
+                    RouteRecord route = mRoutes.get(i);
+                    if (route.getDescriptorId().equals(descriptorId)) {
+                        return i;
+                    }
+                }
+                return -1;
+            }
+
+            public void dump(PrintWriter pw, String prefix) {
+                pw.println(prefix + this);
+
+                final String indent = prefix + "  ";
+                mProvider.dump(pw, indent);
+
+                final int routeCount = mRoutes.size();
+                if (routeCount != 0) {
+                    for (int i = 0; i < routeCount; i++) {
+                        mRoutes.get(i).dump(pw, indent);
+                    }
+                } else {
+                    pw.println(indent + "<no routes>");
+                }
+            }
+
+            @Override
+            public String toString() {
+                return "Provider " + mProvider.getFlattenedComponentName();
+            }
+
+            private String assignRouteUniqueId(String descriptorId) {
+                return mUniquePrefix + descriptorId;
+            }
+        }
+
+        static final class RouteRecord {
+            private final ProviderRecord mProviderRecord;
+            private final String mDescriptorId;
+            private final MediaRouterClientState.RouteInfo mMutableInfo;
+            private MediaRouterClientState.RouteInfo mImmutableInfo;
+            private RemoteDisplayInfo mDescriptor;
+
+            public RouteRecord(ProviderRecord providerRecord,
+                    String descriptorId, String uniqueId) {
+                mProviderRecord = providerRecord;
+                mDescriptorId = descriptorId;
+                mMutableInfo = new MediaRouterClientState.RouteInfo(uniqueId);
+            }
+
+            public RemoteDisplayProviderProxy getProvider() {
+                return mProviderRecord.getProvider();
+            }
+
+            public ProviderRecord getProviderRecord() {
+                return mProviderRecord;
+            }
+
+            public String getDescriptorId() {
+                return mDescriptorId;
+            }
+
+            public String getUniqueId() {
+                return mMutableInfo.id;
+            }
+
+            public MediaRouterClientState.RouteInfo getInfo() {
+                if (mImmutableInfo == null) {
+                    mImmutableInfo = new MediaRouterClientState.RouteInfo(mMutableInfo);
+                }
+                return mImmutableInfo;
+            }
+
+            public boolean isValid() {
+                return mDescriptor != null;
+            }
+
+            public boolean isEnabled() {
+                return mMutableInfo.enabled;
+            }
+
+            public int getStatus() {
+                return mMutableInfo.statusCode;
+            }
+
+            public boolean updateDescriptor(RemoteDisplayInfo descriptor) {
+                boolean changed = false;
+                if (mDescriptor != descriptor) {
+                    mDescriptor = descriptor;
+                    if (descriptor != null) {
+                        final String name = computeName(descriptor);
+                        if (!Objects.equal(mMutableInfo.name, name)) {
+                            mMutableInfo.name = name;
+                            changed = true;
+                        }
+                        final String description = computeDescription(descriptor);
+                        if (!Objects.equal(mMutableInfo.description, description)) {
+                            mMutableInfo.description = description;
+                            changed = true;
+                        }
+                        final int supportedTypes = computeSupportedTypes(descriptor);
+                        if (mMutableInfo.supportedTypes != supportedTypes) {
+                            mMutableInfo.supportedTypes = supportedTypes;
+                            changed = true;
+                        }
+                        final boolean enabled = computeEnabled(descriptor);
+                        if (mMutableInfo.enabled != enabled) {
+                            mMutableInfo.enabled = enabled;
+                            changed = true;
+                        }
+                        final int statusCode = computeStatusCode(descriptor);
+                        if (mMutableInfo.statusCode != statusCode) {
+                            mMutableInfo.statusCode = statusCode;
+                            changed = true;
+                        }
+                        final int playbackType = computePlaybackType(descriptor);
+                        if (mMutableInfo.playbackType != playbackType) {
+                            mMutableInfo.playbackType = playbackType;
+                            changed = true;
+                        }
+                        final int playbackStream = computePlaybackStream(descriptor);
+                        if (mMutableInfo.playbackStream != playbackStream) {
+                            mMutableInfo.playbackStream = playbackStream;
+                            changed = true;
+                        }
+                        final int volume = computeVolume(descriptor);
+                        if (mMutableInfo.volume != volume) {
+                            mMutableInfo.volume = volume;
+                            changed = true;
+                        }
+                        final int volumeMax = computeVolumeMax(descriptor);
+                        if (mMutableInfo.volumeMax != volumeMax) {
+                            mMutableInfo.volumeMax = volumeMax;
+                            changed = true;
+                        }
+                        final int volumeHandling = computeVolumeHandling(descriptor);
+                        if (mMutableInfo.volumeHandling != volumeHandling) {
+                            mMutableInfo.volumeHandling = volumeHandling;
+                            changed = true;
+                        }
+                        final int presentationDisplayId = computePresentationDisplayId(descriptor);
+                        if (mMutableInfo.presentationDisplayId != presentationDisplayId) {
+                            mMutableInfo.presentationDisplayId = presentationDisplayId;
+                            changed = true;
+                        }
+                    }
+                }
+                if (changed) {
+                    mImmutableInfo = null;
+                }
+                return changed;
+            }
+
+            public void dump(PrintWriter pw, String prefix) {
+                pw.println(prefix + this);
+
+                final String indent = prefix + "  ";
+                pw.println(indent + "mMutableInfo=" + mMutableInfo);
+                pw.println(indent + "mDescriptorId=" + mDescriptorId);
+                pw.println(indent + "mDescriptor=" + mDescriptor);
+            }
+
+            @Override
+            public String toString() {
+                return "Route " + mMutableInfo.name + " (" + mMutableInfo.id + ")";
+            }
+
+            private static String computeName(RemoteDisplayInfo descriptor) {
+                // Note that isValid() already ensures the name is non-empty.
+                return descriptor.name;
+            }
+
+            private static String computeDescription(RemoteDisplayInfo descriptor) {
+                final String description = descriptor.description;
+                return TextUtils.isEmpty(description) ? null : description;
+            }
+
+            private static int computeSupportedTypes(RemoteDisplayInfo descriptor) {
+                return MediaRouter.ROUTE_TYPE_LIVE_AUDIO
+                        | MediaRouter.ROUTE_TYPE_LIVE_VIDEO
+                        | MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY;
+            }
+
+            private static boolean computeEnabled(RemoteDisplayInfo descriptor) {
+                switch (descriptor.status) {
+                    case RemoteDisplayInfo.STATUS_CONNECTED:
+                    case RemoteDisplayInfo.STATUS_CONNECTING:
+                    case RemoteDisplayInfo.STATUS_AVAILABLE:
+                        return true;
+                    default:
+                        return false;
+                }
+            }
+
+            private static int computeStatusCode(RemoteDisplayInfo descriptor) {
+                switch (descriptor.status) {
+                    case RemoteDisplayInfo.STATUS_NOT_AVAILABLE:
+                        return MediaRouter.RouteInfo.STATUS_NOT_AVAILABLE;
+                    case RemoteDisplayInfo.STATUS_AVAILABLE:
+                        return MediaRouter.RouteInfo.STATUS_AVAILABLE;
+                    case RemoteDisplayInfo.STATUS_IN_USE:
+                        return MediaRouter.RouteInfo.STATUS_IN_USE;
+                    case RemoteDisplayInfo.STATUS_CONNECTING:
+                        return MediaRouter.RouteInfo.STATUS_CONNECTING;
+                    case RemoteDisplayInfo.STATUS_CONNECTED:
+                        return MediaRouter.RouteInfo.STATUS_CONNECTED;
+                    default:
+                        return MediaRouter.RouteInfo.STATUS_NONE;
+                }
+            }
+
+            private static int computePlaybackType(RemoteDisplayInfo descriptor) {
+                return MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE;
+            }
+
+            private static int computePlaybackStream(RemoteDisplayInfo descriptor) {
+                return AudioSystem.STREAM_MUSIC;
+            }
+
+            private static int computeVolume(RemoteDisplayInfo descriptor) {
+                final int volume = descriptor.volume;
+                final int volumeMax = descriptor.volumeMax;
+                if (volume < 0) {
+                    return 0;
+                } else if (volume > volumeMax) {
+                    return volumeMax;
+                }
+                return volume;
+            }
+
+            private static int computeVolumeMax(RemoteDisplayInfo descriptor) {
+                final int volumeMax = descriptor.volumeMax;
+                return volumeMax > 0 ? volumeMax : 0;
+            }
+
+            private static int computeVolumeHandling(RemoteDisplayInfo descriptor) {
+                final int volumeHandling = descriptor.volumeHandling;
+                switch (volumeHandling) {
+                    case RemoteDisplayInfo.PLAYBACK_VOLUME_VARIABLE:
+                        return MediaRouter.RouteInfo.PLAYBACK_VOLUME_VARIABLE;
+                    case RemoteDisplayInfo.PLAYBACK_VOLUME_FIXED:
+                    default:
+                        return MediaRouter.RouteInfo.PLAYBACK_VOLUME_FIXED;
+                }
+            }
+
+            private static int computePresentationDisplayId(RemoteDisplayInfo descriptor) {
+                // The MediaRouter class validates that the id corresponds to an extant
+                // presentation display.  So all we do here is canonicalize the null case.
+                final int displayId = descriptor.presentationDisplayId;
+                return displayId < 0 ? -1 : displayId;
+            }
+        }
+    }
+}
diff --git a/services/java/com/android/server/media/RemoteDisplayProviderProxy.java b/services/java/com/android/server/media/RemoteDisplayProviderProxy.java
new file mode 100644
index 0000000..b248ee0
--- /dev/null
+++ b/services/java/com/android/server/media/RemoteDisplayProviderProxy.java
@@ -0,0 +1,443 @@
+/*
+ * 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.android.server.media;
+
+import com.android.internal.util.Objects;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.media.IRemoteDisplayCallback;
+import android.media.IRemoteDisplayProvider;
+import android.media.RemoteDisplayState;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.IBinder.DeathRecipient;
+import android.os.UserHandle;
+import android.util.Log;
+import android.util.Slog;
+
+import java.io.PrintWriter;
+import java.lang.ref.WeakReference;
+
+/**
+ * Maintains a connection to a particular remote display provider service.
+ */
+final class RemoteDisplayProviderProxy implements ServiceConnection {
+    private static final String TAG = "RemoteDisplayProvider";  // max. 23 chars
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+    private final Context mContext;
+    private final ComponentName mComponentName;
+    private final int mUserId;
+    private final Handler mHandler;
+
+    private Callback mDisplayStateCallback;
+
+    // Connection state
+    private boolean mRunning;
+    private boolean mBound;
+    private Connection mActiveConnection;
+    private boolean mConnectionReady;
+
+    // Logical state
+    private int mDiscoveryMode;
+    private String mSelectedDisplayId;
+    private RemoteDisplayState mDisplayState;
+    private boolean mScheduledDisplayStateChangedCallback;
+
+    public RemoteDisplayProviderProxy(Context context, ComponentName componentName,
+            int userId) {
+        mContext = context;
+        mComponentName = componentName;
+        mUserId = userId;
+        mHandler = new Handler();
+    }
+
+    public void dump(PrintWriter pw, String prefix) {
+        pw.println(prefix + "Proxy");
+        pw.println(prefix + "  mUserId=" + mUserId);
+        pw.println(prefix + "  mRunning=" + mRunning);
+        pw.println(prefix + "  mBound=" + mBound);
+        pw.println(prefix + "  mActiveConnection=" + mActiveConnection);
+        pw.println(prefix + "  mConnectionReady=" + mConnectionReady);
+        pw.println(prefix + "  mDiscoveryMode=" + mDiscoveryMode);
+        pw.println(prefix + "  mSelectedDisplayId=" + mSelectedDisplayId);
+        pw.println(prefix + "  mDisplayState=" + mDisplayState);
+    }
+
+    public void setCallback(Callback callback) {
+        mDisplayStateCallback = callback;
+    }
+
+    public RemoteDisplayState getDisplayState() {
+        return mDisplayState;
+    }
+
+    public void setDiscoveryMode(int mode) {
+        if (mDiscoveryMode != mode) {
+            mDiscoveryMode = mode;
+            if (mConnectionReady) {
+                mActiveConnection.setDiscoveryMode(mode);
+            }
+            updateBinding();
+        }
+    }
+
+    public void setSelectedDisplay(String id) {
+        if (!Objects.equal(mSelectedDisplayId, id)) {
+            if (mConnectionReady && mSelectedDisplayId != null) {
+                mActiveConnection.disconnect(mSelectedDisplayId);
+            }
+            mSelectedDisplayId = id;
+            if (mConnectionReady && id != null) {
+                mActiveConnection.connect(id);
+            }
+            updateBinding();
+        }
+    }
+
+    public void setDisplayVolume(int volume) {
+        if (mConnectionReady && mSelectedDisplayId != null) {
+            mActiveConnection.setVolume(mSelectedDisplayId, volume);
+        }
+    }
+
+    public void adjustDisplayVolume(int delta) {
+        if (mConnectionReady && mSelectedDisplayId != null) {
+            mActiveConnection.adjustVolume(mSelectedDisplayId, delta);
+        }
+    }
+
+    public boolean hasComponentName(String packageName, String className) {
+        return mComponentName.getPackageName().equals(packageName)
+                && mComponentName.getClassName().equals(className);
+    }
+
+    public String getFlattenedComponentName() {
+        return mComponentName.flattenToShortString();
+    }
+
+    public void start() {
+        if (!mRunning) {
+            if (DEBUG) {
+                Slog.d(TAG, this + ": Starting");
+            }
+
+            mRunning = true;
+            updateBinding();
+        }
+    }
+
+    public void stop() {
+        if (mRunning) {
+            if (DEBUG) {
+                Slog.d(TAG, this + ": Stopping");
+            }
+
+            mRunning = false;
+            updateBinding();
+        }
+    }
+
+    public void rebindIfDisconnected() {
+        if (mActiveConnection == null && shouldBind()) {
+            unbind();
+            bind();
+        }
+    }
+
+    private void updateBinding() {
+        if (shouldBind()) {
+            bind();
+        } else {
+            unbind();
+        }
+    }
+
+    private boolean shouldBind() {
+        if (mRunning) {
+            // Bind whenever there is a discovery request or selected display.
+            if (mDiscoveryMode != RemoteDisplayState.DISCOVERY_MODE_NONE
+                    || mSelectedDisplayId != null) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private void bind() {
+        if (!mBound) {
+            if (DEBUG) {
+                Slog.d(TAG, this + ": Binding");
+            }
+
+            Intent service = new Intent(RemoteDisplayState.SERVICE_INTERFACE);
+            service.setComponent(mComponentName);
+            try {
+                mBound = mContext.bindServiceAsUser(service, this, Context.BIND_AUTO_CREATE,
+                        new UserHandle(mUserId));
+                if (!mBound && DEBUG) {
+                    Slog.d(TAG, this + ": Bind failed");
+                }
+            } catch (SecurityException ex) {
+                if (DEBUG) {
+                    Slog.d(TAG, this + ": Bind failed", ex);
+                }
+            }
+        }
+    }
+
+    private void unbind() {
+        if (mBound) {
+            if (DEBUG) {
+                Slog.d(TAG, this + ": Unbinding");
+            }
+
+            mBound = false;
+            disconnect();
+            mContext.unbindService(this);
+        }
+    }
+
+    @Override
+    public void onServiceConnected(ComponentName name, IBinder service) {
+        if (DEBUG) {
+            Slog.d(TAG, this + ": Connected");
+        }
+
+        if (mBound) {
+            disconnect();
+
+            IRemoteDisplayProvider provider = IRemoteDisplayProvider.Stub.asInterface(service);
+            if (provider != null) {
+                Connection connection = new Connection(provider);
+                if (connection.register()) {
+                    mActiveConnection = connection;
+                } else {
+                    if (DEBUG) {
+                        Slog.d(TAG, this + ": Registration failed");
+                    }
+                }
+            } else {
+                Slog.e(TAG, this + ": Service returned invalid remote display provider binder");
+            }
+        }
+    }
+
+    @Override
+    public void onServiceDisconnected(ComponentName name) {
+        if (DEBUG) {
+            Slog.d(TAG, this + ": Service disconnected");
+        }
+        disconnect();
+    }
+
+    private void onConnectionReady(Connection connection) {
+        if (mActiveConnection == connection) {
+            mConnectionReady = true;
+
+            if (mDiscoveryMode != RemoteDisplayState.DISCOVERY_MODE_NONE) {
+                mActiveConnection.setDiscoveryMode(mDiscoveryMode);
+            }
+            if (mSelectedDisplayId != null) {
+                mActiveConnection.connect(mSelectedDisplayId);
+            }
+        }
+    }
+
+    private void onConnectionDied(Connection connection) {
+        if (mActiveConnection == connection) {
+            if (DEBUG) {
+                Slog.d(TAG, this + ": Service connection died");
+            }
+            disconnect();
+        }
+    }
+
+    private void onDisplayStateChanged(Connection connection, RemoteDisplayState state) {
+        if (mActiveConnection == connection) {
+            if (DEBUG) {
+                Slog.d(TAG, this + ": State changed, state=" + state);
+            }
+            setDisplayState(state);
+        }
+    }
+
+    private void disconnect() {
+        if (mActiveConnection != null) {
+            if (mSelectedDisplayId != null) {
+                mActiveConnection.disconnect(mSelectedDisplayId);
+            }
+            mConnectionReady = false;
+            mActiveConnection.dispose();
+            mActiveConnection = null;
+            setDisplayState(null);
+        }
+    }
+
+    private void setDisplayState(RemoteDisplayState state) {
+        if (!Objects.equal(mDisplayState, state)) {
+            mDisplayState = state;
+            if (!mScheduledDisplayStateChangedCallback) {
+                mScheduledDisplayStateChangedCallback = true;
+                mHandler.post(mDisplayStateChanged);
+            }
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "Service connection " + mComponentName.flattenToShortString();
+    }
+
+    private final Runnable mDisplayStateChanged = new Runnable() {
+        @Override
+        public void run() {
+            mScheduledDisplayStateChangedCallback = false;
+            if (mDisplayStateCallback != null) {
+                mDisplayStateCallback.onDisplayStateChanged(
+                        RemoteDisplayProviderProxy.this, mDisplayState);
+            }
+        }
+    };
+
+    public interface Callback {
+        void onDisplayStateChanged(RemoteDisplayProviderProxy provider, RemoteDisplayState state);
+    }
+
+    private final class Connection implements DeathRecipient {
+        private final IRemoteDisplayProvider mProvider;
+        private final ProviderCallback mCallback;
+
+        public Connection(IRemoteDisplayProvider provider) {
+            mProvider = provider;
+            mCallback = new ProviderCallback(this);
+        }
+
+        public boolean register() {
+            try {
+                mProvider.asBinder().linkToDeath(this, 0);
+                mProvider.setCallback(mCallback);
+                mHandler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        onConnectionReady(Connection.this);
+                    }
+                });
+                return true;
+            } catch (RemoteException ex) {
+                binderDied();
+            }
+            return false;
+        }
+
+        public void dispose() {
+            mProvider.asBinder().unlinkToDeath(this, 0);
+            mCallback.dispose();
+        }
+
+        public void setDiscoveryMode(int mode) {
+            try {
+                mProvider.setDiscoveryMode(mode);
+            } catch (RemoteException ex) {
+                Slog.e(TAG, "Failed to deliver request to set discovery mode.", ex);
+            }
+        }
+
+        public void connect(String id) {
+            try {
+                mProvider.connect(id);
+            } catch (RemoteException ex) {
+                Slog.e(TAG, "Failed to deliver request to connect to display.", ex);
+            }
+        }
+
+        public void disconnect(String id) {
+            try {
+                mProvider.disconnect(id);
+            } catch (RemoteException ex) {
+                Slog.e(TAG, "Failed to deliver request to disconnect from display.", ex);
+            }
+        }
+
+        public void setVolume(String id, int volume) {
+            try {
+                mProvider.setVolume(id, volume);
+            } catch (RemoteException ex) {
+                Slog.e(TAG, "Failed to deliver request to set display volume.", ex);
+            }
+        }
+
+        public void adjustVolume(String id, int volume) {
+            try {
+                mProvider.adjustVolume(id, volume);
+            } catch (RemoteException ex) {
+                Slog.e(TAG, "Failed to deliver request to adjust display volume.", ex);
+            }
+        }
+
+        @Override
+        public void binderDied() {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    onConnectionDied(Connection.this);
+                }
+            });
+        }
+
+        void postStateChanged(final RemoteDisplayState state) {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    onDisplayStateChanged(Connection.this, state);
+                }
+            });
+        }
+    }
+
+    /**
+     * Receives callbacks from the service.
+     * <p>
+     * This inner class is static and only retains a weak reference to the connection
+     * to prevent the client from being leaked in case the service is holding an
+     * active reference to the client's callback.
+     * </p>
+     */
+    private static final class ProviderCallback extends IRemoteDisplayCallback.Stub {
+        private final WeakReference<Connection> mConnectionRef;
+
+        public ProviderCallback(Connection connection) {
+            mConnectionRef = new WeakReference<Connection>(connection);
+        }
+
+        public void dispose() {
+            mConnectionRef.clear();
+        }
+
+        @Override
+        public void onStateChanged(RemoteDisplayState state) throws RemoteException {
+            Connection connection = mConnectionRef.get();
+            if (connection != null) {
+                connection.postStateChanged(state);
+            }
+        }
+    }
+}
diff --git a/services/java/com/android/server/media/RemoteDisplayProviderWatcher.java b/services/java/com/android/server/media/RemoteDisplayProviderWatcher.java
new file mode 100644
index 0000000..f3a3c2f
--- /dev/null
+++ b/services/java/com/android/server/media/RemoteDisplayProviderWatcher.java
@@ -0,0 +1,181 @@
+/*
+ * 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.android.server.media;
+
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.media.RemoteDisplayState;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.util.Log;
+import android.util.Slog;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+
+/**
+ * Watches for remote display provider services to be installed.
+ * Adds a provider to the media router for each registered service.
+ *
+ * @see RemoteDisplayProviderProxy
+ */
+public final class RemoteDisplayProviderWatcher {
+    private static final String TAG = "RemoteDisplayProvider";  // max. 23 chars
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+    private final Context mContext;
+    private final Callback mCallback;
+    private final Handler mHandler;
+    private final int mUserId;
+    private final PackageManager mPackageManager;
+
+    private final ArrayList<RemoteDisplayProviderProxy> mProviders =
+            new ArrayList<RemoteDisplayProviderProxy>();
+    private boolean mRunning;
+
+    public RemoteDisplayProviderWatcher(Context context,
+            Callback callback, Handler handler, int userId) {
+        mContext = context;
+        mCallback = callback;
+        mHandler = handler;
+        mUserId = userId;
+        mPackageManager = context.getPackageManager();
+    }
+
+    public void dump(PrintWriter pw, String prefix) {
+        pw.println(prefix + "Watcher");
+        pw.println(prefix + "  mUserId=" + mUserId);
+        pw.println(prefix + "  mRunning=" + mRunning);
+        pw.println(prefix + "  mProviders.size()=" + mProviders.size());
+    }
+
+    public void start() {
+        if (!mRunning) {
+            mRunning = true;
+
+            IntentFilter filter = new IntentFilter();
+            filter.addAction(Intent.ACTION_PACKAGE_ADDED);
+            filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+            filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+            filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
+            filter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
+            filter.addDataScheme("package");
+            mContext.registerReceiverAsUser(mScanPackagesReceiver,
+                    new UserHandle(mUserId), filter, null, mHandler);
+
+            // Scan packages.
+            // Also has the side-effect of restarting providers if needed.
+            mHandler.post(mScanPackagesRunnable);
+        }
+    }
+
+    public void stop() {
+        if (mRunning) {
+            mRunning = false;
+
+            mContext.unregisterReceiver(mScanPackagesReceiver);
+            mHandler.removeCallbacks(mScanPackagesRunnable);
+
+            // Stop all providers.
+            for (int i = mProviders.size() - 1; i >= 0; i--) {
+                mProviders.get(i).stop();
+            }
+        }
+    }
+
+    private void scanPackages() {
+        if (!mRunning) {
+            return;
+        }
+
+        // Add providers for all new services.
+        // Reorder the list so that providers left at the end will be the ones to remove.
+        int targetIndex = 0;
+        Intent intent = new Intent(RemoteDisplayState.SERVICE_INTERFACE);
+        for (ResolveInfo resolveInfo : mPackageManager.queryIntentServicesAsUser(
+                intent, 0, mUserId)) {
+            ServiceInfo serviceInfo = resolveInfo.serviceInfo;
+            if (serviceInfo != null) {
+                int sourceIndex = findProvider(serviceInfo.packageName, serviceInfo.name);
+                if (sourceIndex < 0) {
+                    RemoteDisplayProviderProxy provider =
+                            new RemoteDisplayProviderProxy(mContext,
+                            new ComponentName(serviceInfo.packageName, serviceInfo.name),
+                            mUserId);
+                    provider.start();
+                    mProviders.add(targetIndex++, provider);
+                    mCallback.addProvider(provider);
+                } else if (sourceIndex >= targetIndex) {
+                    RemoteDisplayProviderProxy provider = mProviders.get(sourceIndex);
+                    provider.start(); // restart the provider if needed
+                    provider.rebindIfDisconnected();
+                    Collections.swap(mProviders, sourceIndex, targetIndex++);
+                }
+            }
+        }
+
+        // Remove providers for missing services.
+        if (targetIndex < mProviders.size()) {
+            for (int i = mProviders.size() - 1; i >= targetIndex; i--) {
+                RemoteDisplayProviderProxy provider = mProviders.get(i);
+                mCallback.removeProvider(provider);
+                mProviders.remove(provider);
+                provider.stop();
+            }
+        }
+    }
+
+    private int findProvider(String packageName, String className) {
+        int count = mProviders.size();
+        for (int i = 0; i < count; i++) {
+            RemoteDisplayProviderProxy provider = mProviders.get(i);
+            if (provider.hasComponentName(packageName, className)) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    private final BroadcastReceiver mScanPackagesReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (DEBUG) {
+                Slog.d(TAG, "Received package manager broadcast: " + intent);
+            }
+            scanPackages();
+        }
+    };
+
+    private final Runnable mScanPackagesRunnable = new Runnable() {
+        @Override
+        public void run() {
+            scanPackages();
+        }
+    };
+
+    public interface Callback {
+        void addProvider(RemoteDisplayProviderProxy provider);
+        void removeProvider(RemoteDisplayProviderProxy provider);
+    }
+}
diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java
index 5d6adc2..271e9e9 100644
--- a/services/java/com/android/server/net/NetworkStatsService.java
+++ b/services/java/com/android/server/net/NetworkStatsService.java
@@ -464,21 +464,21 @@
             private NetworkStatsCollection mUidTagComplete;
 
             private NetworkStatsCollection getUidComplete() {
-                if (mUidComplete == null) {
-                    synchronized (mStatsLock) {
+                synchronized (mStatsLock) {
+                    if (mUidComplete == null) {
                         mUidComplete = mUidRecorder.getOrLoadCompleteLocked();
                     }
+                    return mUidComplete;
                 }
-                return mUidComplete;
             }
 
             private NetworkStatsCollection getUidTagComplete() {
-                if (mUidTagComplete == null) {
-                    synchronized (mStatsLock) {
+                synchronized (mStatsLock) {
+                    if (mUidTagComplete == null) {
                         mUidTagComplete = mUidTagRecorder.getOrLoadCompleteLocked();
                     }
+                    return mUidTagComplete;
                 }
-                return mUidTagComplete;
             }
 
             @Override
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index fdeeebd..5af25c6 100755
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -4959,6 +4959,18 @@
                         permissionMap.put(p.info.name, bp);
                     }
                     if (bp.perm == null) {
+                        if (bp.sourcePackage != null
+                                && !bp.sourcePackage.equals(p.info.packageName)) {
+                            // If this is a permission that was formerly defined by a non-system
+                            // app, but is now defined by a system app (following an upgrade),
+                            // discard the previous declaration and consider the system's to be
+                            // canonical.
+                            if (isSystemApp(p.owner)) {
+                                Slog.i(TAG, "New decl " + p.owner + " of permission  "
+                                        + p.info.name + " is system");
+                                bp.sourcePackage = null;
+                            }
+                        }
                         if (bp.sourcePackage == null
                                 || bp.sourcePackage.equals(p.info.packageName)) {
                             BasePermission tree = findPermissionTreeLP(p.info.name);
diff --git a/services/java/com/android/server/wifi/WifiService.java b/services/java/com/android/server/wifi/WifiService.java
index b7a6c5f..78e9157 100644
--- a/services/java/com/android/server/wifi/WifiService.java
+++ b/services/java/com/android/server/wifi/WifiService.java
@@ -369,15 +369,17 @@
     }
 
     private class BatchedScanRequest extends DeathRecipient {
-        BatchedScanSettings settings;
-        int uid;
-        int pid;
+        final BatchedScanSettings settings;
+        final int uid;
+        final int pid;
+        final WorkSource workSource;
 
-        BatchedScanRequest(BatchedScanSettings settings, IBinder binder) {
+        BatchedScanRequest(BatchedScanSettings settings, IBinder binder, WorkSource ws) {
             super(0, null, binder, null);
             this.settings = settings;
             this.uid = getCallingUid();
             this.pid = getCallingPid();
+            workSource = ws;
         }
         public void binderDied() {
             stopBatchedScan(settings, uid, pid);
@@ -406,12 +408,19 @@
     /**
      * see {@link android.net.wifi.WifiManager#requestBatchedScan()}
      */
-    public boolean requestBatchedScan(BatchedScanSettings requested, IBinder binder) {
+    public boolean requestBatchedScan(BatchedScanSettings requested, IBinder binder,
+            WorkSource workSource) {
         enforceChangePermission();
+        if (workSource != null) {
+            enforceWorkSourcePermission();
+            // WifiManager currently doesn't use names, so need to clear names out of the
+            // supplied WorkSource to allow future WorkSource combining.
+            workSource.clearNames();
+        }
         if (mBatchedScanSupported == false) return false;
         requested = new BatchedScanSettings(requested);
         if (requested.isInvalid()) return false;
-        BatchedScanRequest r = new BatchedScanRequest(requested, binder);
+        BatchedScanRequest r = new BatchedScanRequest(requested, binder, workSource);
         synchronized(mBatchedScanners) {
             mBatchedScanners.add(r);
             resolveBatchedScannersLocked();
@@ -468,18 +477,48 @@
 
     private void resolveBatchedScannersLocked() {
         BatchedScanSettings setting = new BatchedScanSettings();
+        WorkSource responsibleWorkSource = null;
         int responsibleUid = 0;
+        double responsibleCsph = 0; // Channel Scans Per Hour
 
         if (mBatchedScanners.size() == 0) {
-            mWifiStateMachine.setBatchedScanSettings(null, 0);
+            mWifiStateMachine.setBatchedScanSettings(null, 0, 0, null);
             return;
         }
         for (BatchedScanRequest r : mBatchedScanners) {
             BatchedScanSettings s = r.settings;
+
+            // evaluate responsibility
+            int currentChannelCount;
+            int currentScanInterval;
+            double currentCsph;
+
+            if (s.channelSet == null || s.channelSet.isEmpty()) {
+                // all channels - 11 B and 9 A channels roughly.
+                currentChannelCount = 9 + 11;
+            } else {
+                currentChannelCount = s.channelSet.size();
+                // these are rough est - no real need to correct for reg-domain;
+                if (s.channelSet.contains("A")) currentChannelCount += (9 - 1);
+                if (s.channelSet.contains("B")) currentChannelCount += (11 - 1);
+
+            }
+            if (s.scanIntervalSec == BatchedScanSettings.UNSPECIFIED) {
+                currentScanInterval = BatchedScanSettings.DEFAULT_INTERVAL_SEC;
+            } else {
+                currentScanInterval = s.scanIntervalSec;
+            }
+            currentCsph = 60 * 60 * currentChannelCount / currentScanInterval;
+
+            if (currentCsph > responsibleCsph) {
+                responsibleUid = r.uid;
+                responsibleWorkSource = r.workSource;
+                responsibleCsph = currentCsph;
+            }
+
             if (s.maxScansPerBatch != BatchedScanSettings.UNSPECIFIED &&
                     s.maxScansPerBatch < setting.maxScansPerBatch) {
                 setting.maxScansPerBatch = s.maxScansPerBatch;
-                responsibleUid = r.uid;
             }
             if (s.maxApPerScan != BatchedScanSettings.UNSPECIFIED &&
                     (setting.maxApPerScan == BatchedScanSettings.UNSPECIFIED ||
@@ -489,7 +528,6 @@
             if (s.scanIntervalSec != BatchedScanSettings.UNSPECIFIED &&
                     s.scanIntervalSec < setting.scanIntervalSec) {
                 setting.scanIntervalSec = s.scanIntervalSec;
-                responsibleUid = r.uid;
             }
             if (s.maxApForDistance != BatchedScanSettings.UNSPECIFIED &&
                     (setting.maxApForDistance == BatchedScanSettings.UNSPECIFIED ||
@@ -511,7 +549,8 @@
         }
 
         setting.constrain();
-        mWifiStateMachine.setBatchedScanSettings(setting, responsibleUid);
+        mWifiStateMachine.setBatchedScanSettings(setting, responsibleUid, (int)responsibleCsph,
+                responsibleWorkSource);
     }
 
     private void enforceAccessPermission() {
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 7f0d55f..194a0bb 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -575,10 +575,13 @@
         private boolean mUpdateRotation = false;
         boolean mWallpaperActionPending = false;
 
-        private static final int DISPLAY_CONTENT_UNKNOWN = 0;
-        private static final int DISPLAY_CONTENT_MIRROR = 1;
-        private static final int DISPLAY_CONTENT_UNIQUE = 2;
-        private int mDisplayHasContent = DISPLAY_CONTENT_UNKNOWN;
+        // Set to true when the display contains content to show the user.
+        // When false, the display manager may choose to mirror or blank the display.
+        boolean mDisplayHasContent = false;
+
+        // Only set while traversing the default display based on its content.
+        // Affects the behavior of mirroring on secondary displays.
+        boolean mObscureApplicationContentOnSecondaryDisplays = false;
     }
     final LayoutFields mInnerFields = new LayoutFields();
 
@@ -8767,6 +8770,14 @@
         final WindowManager.LayoutParams attrs = w.mAttrs;
         final int attrFlags = attrs.flags;
         final boolean canBeSeen = w.isDisplayedLw();
+        final boolean opaqueDrawn = canBeSeen && w.isOpaqueDrawn();
+
+        if (opaqueDrawn && w.isFullscreen(innerDw, innerDh)) {
+            // This window completely covers everything behind it,
+            // so we want to leave all of them as undimmed (for
+            // performance reasons).
+            mInnerFields.mObscured = true;
+        }
 
         if (w.mHasSurface) {
             if ((attrFlags&FLAG_KEEP_SCREEN_ON) != 0) {
@@ -8795,22 +8806,24 @@
             }
 
             if (canBeSeen) {
-                if (type == TYPE_DREAM || type == TYPE_KEYGUARD) {
-                    mInnerFields.mDisplayHasContent = LayoutFields.DISPLAY_CONTENT_MIRROR;
-                } else if (mInnerFields.mDisplayHasContent
-                        == LayoutFields.DISPLAY_CONTENT_UNKNOWN) {
-                    mInnerFields.mDisplayHasContent = LayoutFields.DISPLAY_CONTENT_UNIQUE;
+                // This function assumes that the contents of the default display are
+                // processed first before secondary displays.
+                if (w.mDisplayContent.isDefaultDisplay) {
+                    // While a dream or keyguard is showing, obscure ordinary application
+                    // content on secondary displays (by forcibly enabling mirroring unless
+                    // there is other content we want to show) but still allow opaque
+                    // keyguard dialogs to be shown.
+                    if (type == TYPE_DREAM || type == TYPE_KEYGUARD) {
+                        mInnerFields.mObscureApplicationContentOnSecondaryDisplays = true;
+                    }
+                    mInnerFields.mDisplayHasContent = true;
+                } else if (!mInnerFields.mObscureApplicationContentOnSecondaryDisplays
+                        || (mInnerFields.mObscured && type == TYPE_KEYGUARD_DIALOG)) {
+                    // Allow full screen keyguard presentation dialogs to be seen.
+                    mInnerFields.mDisplayHasContent = true;
                 }
             }
         }
-
-        boolean opaqueDrawn = canBeSeen && w.isOpaqueDrawn();
-        if (opaqueDrawn && w.isFullscreen(innerDw, innerDh)) {
-            // This window completely covers everything behind it,
-            // so we want to leave all of them as undimmed (for
-            // performance reasons).
-            mInnerFields.mObscured = true;
-        }
     }
 
     private void handleFlagDimBehind(WindowState w, int innerDw, int innerDh) {
@@ -8888,7 +8901,7 @@
         mInnerFields.mScreenBrightness = -1;
         mInnerFields.mButtonBrightness = -1;
         mInnerFields.mUserActivityTimeout = -1;
-        mInnerFields.mDisplayHasContent = LayoutFields.DISPLAY_CONTENT_UNKNOWN;
+        mInnerFields.mObscureApplicationContentOnSecondaryDisplays = false;
 
         mTransactionSequence++;
 
@@ -8923,10 +8936,8 @@
                 final int innerDh = displayInfo.appHeight;
                 final boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY);
 
-                // Reset for each display unless we are forcing mirroring.
-                if (mInnerFields.mDisplayHasContent != LayoutFields.DISPLAY_CONTENT_MIRROR) {
-                    mInnerFields.mDisplayHasContent = LayoutFields.DISPLAY_CONTENT_UNKNOWN;
-                }
+                // Reset for each display.
+                mInnerFields.mDisplayHasContent = false;
 
                 int repeats = 0;
                 do {
@@ -9135,20 +9146,8 @@
                     updateResizingWindows(w);
                 }
 
-                final boolean hasUniqueContent;
-                switch (mInnerFields.mDisplayHasContent) {
-                    case LayoutFields.DISPLAY_CONTENT_MIRROR:
-                        hasUniqueContent = isDefaultDisplay;
-                        break;
-                    case LayoutFields.DISPLAY_CONTENT_UNIQUE:
-                        hasUniqueContent = true;
-                        break;
-                    case LayoutFields.DISPLAY_CONTENT_UNKNOWN:
-                    default:
-                        hasUniqueContent = false;
-                        break;
-                }
-                mDisplayManagerService.setDisplayHasContent(displayId, hasUniqueContent,
+                mDisplayManagerService.setDisplayHasContent(displayId,
+                        mInnerFields.mDisplayHasContent,
                         true /* inTraversal, must call performTraversalInTrans... below */);
 
                 getDisplayContentLocked(displayId).stopDimmingIfNeeded();
diff --git a/tests/RemoteDisplayProvider/Android.mk b/tests/RemoteDisplayProvider/Android.mk
new file mode 100644
index 0000000..77e9815
--- /dev/null
+++ b/tests/RemoteDisplayProvider/Android.mk
@@ -0,0 +1,25 @@
+# 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.
+
+LOCAL_PATH := $(call my-dir)
+
+# Build the application.
+include $(CLEAR_VARS)
+LOCAL_PACKAGE_NAME := RemoteDisplayProviderTest
+LOCAL_MODULE_TAGS := tests
+LOCAL_SDK_VERSION := current
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_RESOURCE_DIR = $(LOCAL_PATH)/res
+LOCAL_JAVA_LIBRARIES := com.android.media.remotedisplay
+include $(BUILD_PACKAGE)
diff --git a/tests/RemoteDisplayProvider/AndroidManifest.xml b/tests/RemoteDisplayProvider/AndroidManifest.xml
new file mode 100644
index 0000000..e8e31da
--- /dev/null
+++ b/tests/RemoteDisplayProvider/AndroidManifest.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.android.media.remotedisplay.test" >
+
+    <uses-sdk android:minSdkVersion="19" />
+
+    <application android:label="@string/app_name"
+            android:icon="@drawable/ic_app">
+        <uses-library android:name="com.android.media.remotedisplay"
+                android:required="true" />
+
+        <service android:name=".RemoteDisplayProviderService"
+                android:label="@string/app_name"
+                android:exported="true"
+                android:permission="android.permission.BIND_REMOTE_DISPLAY">
+            <intent-filter>
+                <action android:name="com.android.media.remotedisplay.RemoteDisplayProvider"/>
+            </intent-filter>
+        </service>
+
+    </application>
+</manifest>
diff --git a/tests/RemoteDisplayProvider/README b/tests/RemoteDisplayProvider/README
new file mode 100644
index 0000000..8bf0130
--- /dev/null
+++ b/tests/RemoteDisplayProvider/README
@@ -0,0 +1,16 @@
+This directory contains sample code to test system integration with
+remote display providers using the API declared by the
+com.android.media.remotedisplay.jar library.
+
+--- DESCRIPTION ---
+
+The application registers a service that publishes a few different
+remote display routes.  Behavior can be controlled by modifying the
+code.
+
+To exercise the provider, use System UI features for connecting to
+wireless displays or launch an activity that uses the MediaRouter,
+such as the PresentationWithMediaRouterActivity in ApiDemos.
+
+This code is mainly intended for development and not meant to be
+used as an example implementation of a robust remote display provider.
diff --git a/tests/RemoteDisplayProvider/res/drawable-hdpi/ic_app.png b/tests/RemoteDisplayProvider/res/drawable-hdpi/ic_app.png
new file mode 100755
index 0000000..66a1984
--- /dev/null
+++ b/tests/RemoteDisplayProvider/res/drawable-hdpi/ic_app.png
Binary files differ
diff --git a/tests/RemoteDisplayProvider/res/drawable-mdpi/ic_app.png b/tests/RemoteDisplayProvider/res/drawable-mdpi/ic_app.png
new file mode 100644
index 0000000..5ae7701
--- /dev/null
+++ b/tests/RemoteDisplayProvider/res/drawable-mdpi/ic_app.png
Binary files differ
diff --git a/tests/RemoteDisplayProvider/res/values/strings.xml b/tests/RemoteDisplayProvider/res/values/strings.xml
new file mode 100644
index 0000000..dd82d2c
--- /dev/null
+++ b/tests/RemoteDisplayProvider/res/values/strings.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name">Remote Display Provider Test</string>
+</resources>
diff --git a/tests/RemoteDisplayProvider/src/com/android/media/remotedisplay/test/RemoteDisplayProviderService.java b/tests/RemoteDisplayProvider/src/com/android/media/remotedisplay/test/RemoteDisplayProviderService.java
new file mode 100644
index 0000000..bf84631
--- /dev/null
+++ b/tests/RemoteDisplayProvider/src/com/android/media/remotedisplay/test/RemoteDisplayProviderService.java
@@ -0,0 +1,240 @@
+/*
+ * 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.android.media.remotedisplay.test;
+
+import com.android.media.remotedisplay.RemoteDisplay;
+import com.android.media.remotedisplay.RemoteDisplayProvider;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.IBinder;
+import android.util.Log;
+
+/**
+ * Remote display provider implementation that publishes working routes.
+ */
+public class RemoteDisplayProviderService extends Service {
+    private static final String TAG = "RemoteDisplayProviderTest";
+
+    private Provider mProvider;
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        if (intent.getAction().equals(RemoteDisplayProvider.SERVICE_INTERFACE)) {
+            if (mProvider == null) {
+                mProvider = new Provider();
+                return mProvider.getBinder();
+            }
+        }
+        return null;
+    }
+
+    final class Provider extends RemoteDisplayProvider {
+        private RemoteDisplay mTestDisplay1; // variable volume
+        private RemoteDisplay mTestDisplay2; // fixed volume
+        private RemoteDisplay mTestDisplay3; // not available
+        private RemoteDisplay mTestDisplay4; // in use
+        private RemoteDisplay mTestDisplay5; // available but ignores request to connect
+        private RemoteDisplay mTestDisplay6; // available but never finishes connecting
+        private RemoteDisplay mTestDisplay7; // blinks in and out of existence
+
+        private final Handler mHandler;
+        private boolean mBlinking;
+
+        public Provider() {
+            super(RemoteDisplayProviderService.this);
+            mHandler = new Handler(getMainLooper());
+        }
+
+        @Override
+        public void onDiscoveryModeChanged(int mode) {
+            Log.d(TAG, "onDiscoveryModeChanged: mode=" + mode);
+
+            if (mode != DISCOVERY_MODE_NONE) {
+                // When discovery begins, go find all of the routes.
+                if (mTestDisplay1 == null) {
+                    mTestDisplay1 = new RemoteDisplay("testDisplay1",
+                            "Test Display 1 (variable)");
+                    mTestDisplay1.setDescription("Variable volume");
+                    mTestDisplay1.setStatus(RemoteDisplay.STATUS_AVAILABLE);
+                    mTestDisplay1.setVolume(10);
+                    mTestDisplay1.setVolumeHandling(RemoteDisplay.PLAYBACK_VOLUME_VARIABLE);
+                    mTestDisplay1.setVolumeMax(15);
+                    addDisplay(mTestDisplay1);
+                }
+                if (mTestDisplay2 == null) {
+                    mTestDisplay2 = new RemoteDisplay("testDisplay2",
+                            "Test Display 2 (fixed)");
+                    mTestDisplay2.setDescription("Fixed volume");
+                    mTestDisplay2.setStatus(RemoteDisplay.STATUS_AVAILABLE);
+                    addDisplay(mTestDisplay2);
+                }
+                if (mTestDisplay3 == null) {
+                    mTestDisplay3 = new RemoteDisplay("testDisplay3",
+                            "Test Display 3 (unavailable)");
+                    mTestDisplay3.setDescription("Always unavailable");
+                    mTestDisplay3.setStatus(RemoteDisplay.STATUS_NOT_AVAILABLE);
+                    addDisplay(mTestDisplay3);
+                }
+                if (mTestDisplay4 == null) {
+                    mTestDisplay4 = new RemoteDisplay("testDisplay4",
+                            "Test Display 4 (in-use)");
+                    mTestDisplay4.setDescription("Always in-use");
+                    mTestDisplay4.setStatus(RemoteDisplay.STATUS_IN_USE);
+                    addDisplay(mTestDisplay4);
+                }
+                if (mTestDisplay5 == null) {
+                    mTestDisplay5 = new RemoteDisplay("testDisplay5",
+                            "Test Display 5 (connect ignored)");
+                    mTestDisplay5.setDescription("Ignores connect");
+                    mTestDisplay5.setStatus(RemoteDisplay.STATUS_AVAILABLE);
+                    addDisplay(mTestDisplay5);
+                }
+                if (mTestDisplay6 == null) {
+                    mTestDisplay6 = new RemoteDisplay("testDisplay6",
+                            "Test Display 6 (connect hangs)");
+                    mTestDisplay6.setDescription("Never finishes connecting");
+                    mTestDisplay6.setStatus(RemoteDisplay.STATUS_AVAILABLE);
+                    addDisplay(mTestDisplay6);
+                }
+            } else {
+                // When discovery ends, go hide some of the routes we can't actually use.
+                // This isn't something a normal route provider would do though.
+                // The routes will usually stay published.
+                if (mTestDisplay3 != null) {
+                    removeDisplay(mTestDisplay3);
+                    mTestDisplay3 = null;
+                }
+                if (mTestDisplay4 != null) {
+                    removeDisplay(mTestDisplay4);
+                    mTestDisplay4 = null;
+                }
+            }
+
+            // When active discovery is on, pretend there's a route that we can't quite
+            // reach that blinks in and out of existence.
+            if (mode == DISCOVERY_MODE_ACTIVE) {
+                if (!mBlinking) {
+                    mBlinking = true;
+                    mHandler.post(mBlink);
+                }
+            } else {
+                mBlinking = false;
+            }
+        }
+
+        @Override
+        public void onConnect(final RemoteDisplay display) {
+            Log.d(TAG, "onConnect: display.getId()=" + display.getId());
+
+            if (display == mTestDisplay1 || display == mTestDisplay2) {
+                display.setStatus(RemoteDisplay.STATUS_CONNECTING);
+                mHandler.postDelayed(new Runnable() {
+                    @Override
+                    public void run() {
+                        if ((display == mTestDisplay1 || display == mTestDisplay2)
+                                && display.getStatus() == RemoteDisplay.STATUS_CONNECTING) {
+                            display.setStatus(RemoteDisplay.STATUS_CONNECTED);
+                            updateDisplay(display);
+                        }
+                    }
+                }, 2000);
+                updateDisplay(display);
+            }
+            if (display == mTestDisplay6 || display == mTestDisplay7) {
+                // never finishes connecting
+                display.setStatus(RemoteDisplay.STATUS_CONNECTING);
+                updateDisplay(display);
+            }
+        }
+
+        @Override
+        public void onDisconnect(RemoteDisplay display) {
+            Log.d(TAG, "onDisconnect: display.getId()=" + display.getId());
+
+            if (display == mTestDisplay1 || display == mTestDisplay2
+                    || display == mTestDisplay6) {
+                display.setStatus(RemoteDisplay.STATUS_AVAILABLE);
+                updateDisplay(display);
+            }
+        }
+
+        @Override
+        public void onSetVolume(RemoteDisplay display, int volume) {
+            Log.d(TAG, "onSetVolume: display.getId()=" + display.getId()
+                    + ", volume=" + volume);
+
+            if (display == mTestDisplay1) {
+                display.setVolume(Math.max(0, Math.min(display.getVolumeMax(), volume)));
+                updateDisplay(display);
+            }
+        }
+
+        @Override
+        public void onAdjustVolume(RemoteDisplay display, int delta) {
+            Log.d(TAG, "onAdjustVolume: display.getId()=" + display.getId()
+                    + ", delta=" + delta);
+
+            if (display == mTestDisplay1) {
+                display.setVolume(Math.max(0, Math.min(display.getVolumeMax(),
+                        display .getVolume() + delta)));
+                updateDisplay(display);
+            }
+        }
+
+        @Override
+        public void addDisplay(RemoteDisplay display) {
+            Log.d(TAG, "addDisplay: display=" + display);
+            super.addDisplay(display);
+        }
+
+        @Override
+        public void removeDisplay(RemoteDisplay display) {
+            Log.d(TAG, "removeDisplay: display=" + display);
+            super.removeDisplay(display);
+        }
+
+        @Override
+        public void updateDisplay(RemoteDisplay display) {
+            Log.d(TAG, "updateDisplay: display=" + display);
+            super.updateDisplay(display);
+        }
+
+        private final Runnable mBlink = new Runnable() {
+            @Override
+            public void run() {
+                if (mTestDisplay7 == null) {
+                    if (mBlinking) {
+                        mTestDisplay7 = new RemoteDisplay("testDisplay7",
+                                "Test Display 7 (blinky)");
+                        mTestDisplay7.setDescription("Comes and goes but can't connect");
+                        mTestDisplay7.setStatus(RemoteDisplay.STATUS_AVAILABLE);
+                        addDisplay(mTestDisplay7);
+                        mHandler.postDelayed(this, 7000);
+                    }
+                } else {
+                    removeDisplay(mTestDisplay7);
+                    mTestDisplay7 = null;
+                    if (mBlinking) {
+                        mHandler.postDelayed(this, 4000);
+                    }
+                }
+            }
+        };
+    }
+}
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index bfcc208..4a6b1ff 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -115,7 +115,7 @@
 
     void enableTdlsWithMacAddress(String remoteMacAddress, boolean enable);
 
-    boolean requestBatchedScan(in BatchedScanSettings requested, IBinder binder);
+    boolean requestBatchedScan(in BatchedScanSettings requested, IBinder binder, in WorkSource ws);
 
     void stopBatchedScan(in BatchedScanSettings requested);
 
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 1fa7e85..4c887cb 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -799,7 +799,13 @@
      */
     public boolean requestBatchedScan(BatchedScanSettings requested) {
         try {
-            return mService.requestBatchedScan(requested, new Binder());
+            return mService.requestBatchedScan(requested, new Binder(), null);
+        } catch (RemoteException e) { return false; }
+    }
+    /** @hide */
+    public boolean requestBatchedScan(BatchedScanSettings requested, WorkSource workSource) {
+        try {
+            return mService.requestBatchedScan(requested, new Binder(), workSource);
         } catch (RemoteException e) { return false; }
     }
 
diff --git a/wifi/java/android/net/wifi/WifiNative.java b/wifi/java/android/net/wifi/WifiNative.java
index 520668e..c2f278a 100644
--- a/wifi/java/android/net/wifi/WifiNative.java
+++ b/wifi/java/android/net/wifi/WifiNative.java
@@ -39,7 +39,6 @@
 public class WifiNative {
 
     private static final boolean DBG = false;
-    private static final boolean VDBG = false;
     private final String mTAG;
     private static final int DEFAULT_GROUP_OWNER_INTENT     = 6;
 
@@ -118,12 +117,12 @@
 
     public boolean connectToSupplicant() {
         // No synchronization necessary .. it is implemented in WifiMonitor
-        if (VDBG) localLog(mInterfacePrefix + "connectToSupplicant");
+        localLog(mInterfacePrefix + "connectToSupplicant");
         return connectToSupplicantNative();
     }
 
     public void closeSupplicantConnection() {
-        if (VDBG) localLog(mInterfacePrefix + "closeSupplicantConnection");
+        localLog(mInterfacePrefix + "closeSupplicantConnection");
         closeSupplicantConnectionNative();
     }
 
@@ -136,9 +135,9 @@
         if (DBG) Log.d(mTAG, "doBoolean: " + command);
         synchronized (mLock) {
             int cmdId = getNewCmdIdLocked();
-            if (VDBG) localLog(cmdId + "->" + mInterfacePrefix + command);
+            localLog(cmdId + "->" + mInterfacePrefix + command);
             boolean result = doBooleanCommandNative(mInterfacePrefix + command);
-            if (VDBG) localLog(cmdId + "<-" + result);
+            localLog(cmdId + "<-" + result);
             if (DBG) Log.d(mTAG, "   returned " + result);
             return result;
         }
@@ -148,9 +147,9 @@
         if (DBG) Log.d(mTAG, "doInt: " + command);
         synchronized (mLock) {
             int cmdId = getNewCmdIdLocked();
-            if (VDBG) localLog(cmdId + "->" + mInterfacePrefix + command);
+            localLog(cmdId + "->" + mInterfacePrefix + command);
             int result = doIntCommandNative(mInterfacePrefix + command);
-            if (VDBG) localLog(cmdId + "<-" + result);
+            localLog(cmdId + "<-" + result);
             if (DBG) Log.d(mTAG, "   returned " + result);
             return result;
         }
@@ -160,9 +159,9 @@
         if (DBG) Log.d(mTAG, "doString: " + command);
         synchronized (mLock) {
             int cmdId = getNewCmdIdLocked();
-            if (VDBG) localLog(cmdId + "->" + mInterfacePrefix + command);
+            localLog(cmdId + "->" + mInterfacePrefix + command);
             String result = doStringCommandNative(mInterfacePrefix + command);
-            if (VDBG) localLog(cmdId + "<-" + result);
+            localLog(cmdId + "<-" + result);
             if (DBG) Log.d(mTAG, "   returned " + result);
             return result;
         }
@@ -298,7 +297,9 @@
      * the firmware can remember before it runs out of buffer space or -1 on error
      */
     public String setBatchedScanSettings(BatchedScanSettings settings) {
-        if (settings == null) return doStringCommand("DRIVER WLS_BATCHING STOP");
+        if (settings == null) {
+            return doStringCommand("DRIVER WLS_BATCHING STOP");
+        }
         String cmd = "DRIVER WLS_BATCHING SET SCANFREQ=" + settings.scanIntervalSec;
         cmd += " MSCAN=" + settings.maxScansPerBatch;
         if (settings.maxApPerScan != BatchedScanSettings.UNSPECIFIED) {
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index 8c92e55..4f2af78 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -56,6 +56,8 @@
 import android.net.wifi.p2p.WifiP2pManager;
 import android.net.wifi.p2p.WifiP2pService;
 import android.os.BatteryStats;
+import android.os.Binder;
+import android.os.Bundle;
 import android.os.IBinder;
 import android.os.INetworkManagementService;
 import android.os.Message;
@@ -410,7 +412,8 @@
 
     /* change the batch scan settings.
      * arg1 = responsible UID
-     * obj = the new settings
+     * arg2 = csph (channel scans per hour)
+     * obj = bundle with the new settings and the optional worksource
      */
     public static final int CMD_SET_BATCHED_SCAN          = BASE + 135;
     public static final int CMD_START_NEXT_BATCHED_SCAN   = BASE + 136;
@@ -620,6 +623,15 @@
 
     private BatchedScanSettings mBatchedScanSettings = null;
 
+    /**
+     * Track the worksource/cost of the current settings and track what's been noted
+     * to the battery stats, so we can mark the end of the previous when changing.
+     */
+    private WorkSource mBatchedScanWorkSource = null;
+    private int mBatchedScanCsph = 0;
+    private WorkSource mNotedBatchedScanWorkSource = null;
+    private int mNotedBatchedScanCsph = 0;
+
 
     public WifiStateMachine(Context context, String wlanInterface) {
         super("WifiStateMachine");
@@ -832,8 +844,14 @@
     /**
      * start or stop batched scanning using the given settings
      */
-    public void setBatchedScanSettings(BatchedScanSettings settings, int callingUid) {
-        sendMessage(CMD_SET_BATCHED_SCAN, callingUid, 0, settings);
+    private static final String BATCHED_SETTING = "batched_settings";
+    private static final String BATCHED_WORKSOURCE = "batched_worksource";
+    public void setBatchedScanSettings(BatchedScanSettings settings, int callingUid, int csph,
+            WorkSource workSource) {
+        Bundle bundle = new Bundle();
+        bundle.putParcelable(BATCHED_SETTING, settings);
+        bundle.putParcelable(BATCHED_WORKSOURCE, workSource);
+        sendMessage(CMD_SET_BATCHED_SCAN, callingUid, csph, bundle);
     }
 
     public List<BatchedScanResult> syncGetBatchedScanResultsList() {
@@ -852,6 +870,8 @@
     }
 
     private void startBatchedScan() {
+        if (mBatchedScanSettings == null) return;
+
         if (mDhcpActive) {
             if (DBG) log("not starting Batched Scans due to DHCP");
             return;
@@ -863,10 +883,10 @@
         mAlarmManager.cancel(mBatchedScanIntervalIntent);
 
         String scansExpected = mWifiNative.setBatchedScanSettings(mBatchedScanSettings);
-
         try {
             mExpectedBatchedScans = Integer.parseInt(scansExpected);
             setNextBatchedAlarm(mExpectedBatchedScans);
+            if (mExpectedBatchedScans > 0) noteBatchedScanStart();
         } catch (NumberFormatException e) {
             stopBatchedScan();
             loge("Exception parsing WifiNative.setBatchedScanSettings response " + e);
@@ -909,25 +929,31 @@
     }
 
     // return true if new/different
-    private boolean recordBatchedScanSettings(BatchedScanSettings settings) {
-        if (DBG) log("set batched scan to " + settings);
+    private boolean recordBatchedScanSettings(int responsibleUid, int csph, Bundle bundle) {
+        BatchedScanSettings settings = bundle.getParcelable(BATCHED_SETTING);
+        WorkSource responsibleWorkSource = bundle.getParcelable(BATCHED_WORKSOURCE);
+
+        if (DBG) {
+            log("set batched scan to " + settings + " for uid=" + responsibleUid +
+                    ", worksource=" + responsibleWorkSource);
+        }
         if (settings != null) {
-            // TODO - noteBatchedScanStart(message.arg1);
             if (settings.equals(mBatchedScanSettings)) return false;
         } else {
             if (mBatchedScanSettings == null) return false;
-            // TODO - noteBatchedScanStop(message.arg1);
         }
         mBatchedScanSettings = settings;
+        if (responsibleWorkSource == null) responsibleWorkSource = new WorkSource(responsibleUid);
+        mBatchedScanWorkSource = responsibleWorkSource;
+        mBatchedScanCsph = csph;
         return true;
     }
 
     private void stopBatchedScan() {
         mAlarmManager.cancel(mBatchedScanIntervalIntent);
-        if (mBatchedScanSettings != null) {
-            retrieveBatchedScanData();
-            mWifiNative.setBatchedScanSettings(null);
-        }
+        retrieveBatchedScanData();
+        mWifiNative.setBatchedScanSettings(null);
+        noteBatchedScanStop();
     }
 
     private void setNextBatchedAlarm(int scansExpected) {
@@ -1155,6 +1181,44 @@
         }
     }
 
+    private void noteBatchedScanStart() {
+        // note the end of a previous scan set
+        if (mNotedBatchedScanWorkSource != null &&
+                (mNotedBatchedScanWorkSource.equals(mBatchedScanWorkSource) == false ||
+                 mNotedBatchedScanCsph != mBatchedScanCsph)) {
+            try {
+                mBatteryStats.noteWifiBatchedScanStoppedFromSource(mNotedBatchedScanWorkSource);
+            } catch (RemoteException e) {
+                log(e.toString());
+            } finally {
+                mNotedBatchedScanWorkSource = null;
+                mNotedBatchedScanCsph = 0;
+            }
+        }
+        // note the start of the new
+        try {
+            mBatteryStats.noteWifiBatchedScanStartedFromSource(mBatchedScanWorkSource,
+                    mBatchedScanCsph);
+            mNotedBatchedScanWorkSource = mBatchedScanWorkSource;
+            mNotedBatchedScanCsph = mBatchedScanCsph;
+        } catch (RemoteException e) {
+            log(e.toString());
+        }
+    }
+
+    private void noteBatchedScanStop() {
+        if (mNotedBatchedScanWorkSource != null) {
+            try {
+                mBatteryStats.noteWifiBatchedScanStoppedFromSource(mNotedBatchedScanWorkSource);
+            } catch (RemoteException e) {
+                log(e.toString());
+            } finally {
+                mNotedBatchedScanWorkSource = null;
+                mNotedBatchedScanCsph = 0;
+            }
+        }
+    }
+
     private void startScanNative(int type) {
         mWifiNative.scan(type);
         mScanResultIsPending = true;
@@ -1855,6 +1919,9 @@
            return;
         }
 
+        // note that all these splits and substrings keep references to the original
+        // huge string buffer while the amount we really want is generally pretty small
+        // so make copies instead (one example b/11087956 wasted 400k of heap here).
         synchronized(mScanResultCache) {
             mScanResults = new ArrayList<ScanResult>();
             String[] lines = scanResults.split("\n");
@@ -2294,9 +2361,7 @@
 
         mDhcpActive = false;
 
-        if (mBatchedScanSettings != null) {
-            startBatchedScan();
-        }
+        startBatchedScan();
     }
 
     private void handleSuccessfulIpConfiguration(DhcpResults dhcpResults) {
@@ -2434,7 +2499,7 @@
                     }
                     break;
                 case CMD_SET_BATCHED_SCAN:
-                    recordBatchedScanSettings((BatchedScanSettings)message.obj);
+                    recordBatchedScanSettings(message.arg1, message.arg2, (Bundle)message.obj);
                     break;
                 case CMD_POLL_BATCHED_SCAN:
                     handleBatchedScanPollRequest();
@@ -2946,9 +3011,7 @@
 
             mDhcpActive = false;
 
-            if (mBatchedScanSettings != null) {
-                startBatchedScan();
-            }
+            startBatchedScan();
 
             if (mOperationalMode != CONNECT_MODE) {
                 mWifiNative.disconnect();
@@ -3007,8 +3070,10 @@
                     startScanNative(WifiNative.SCAN_WITH_CONNECTION_SETUP);
                     break;
                 case CMD_SET_BATCHED_SCAN:
-                    recordBatchedScanSettings((BatchedScanSettings)message.obj);
-                    startBatchedScan();
+                    if (recordBatchedScanSettings(message.arg1, message.arg2,
+                            (Bundle)message.obj)) {
+                        startBatchedScan();
+                    }
                     break;
                 case CMD_SET_COUNTRY_CODE:
                     String country = (String) message.obj;
@@ -3146,9 +3211,7 @@
             updateBatteryWorkSource(null);
             mScanResults = new ArrayList<ScanResult>();
 
-            if (mBatchedScanSettings != null) {
-                stopBatchedScan();
-            }
+            stopBatchedScan();
 
             final Intent intent = new Intent(WifiManager.WIFI_SCAN_AVAILABLE);
             intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);