am 49538def: am 79e0206e: Merge "Init the static member when first used for CursorWindow."

* commit '49538def98520eb57d4fb634bf09b2f3104e7953':
  Init the static member when first used for CursorWindow.
diff --git a/Android.mk b/Android.mk
index 1db4365..494ba1b 100644
--- a/Android.mk
+++ b/Android.mk
@@ -59,6 +59,8 @@
 	core/java/android/accounts/IAccountManagerResponse.aidl \
 	core/java/android/accounts/IAccountAuthenticator.aidl \
 	core/java/android/accounts/IAccountAuthenticatorResponse.aidl \
+	core/java/android/app/IActivityContainer.aidl \
+	core/java/android/app/IActivityContainerCallback.aidl \
 	core/java/android/app/IActivityController.aidl \
 	core/java/android/app/IActivityPendingResult.aidl \
 	core/java/android/app/IAlarmManager.aidl \
@@ -128,6 +130,8 @@
 	core/java/android/hardware/ISerialManager.aidl \
 	core/java/android/hardware/display/IDisplayManager.aidl \
 	core/java/android/hardware/display/IDisplayManagerCallback.aidl \
+	core/java/android/hardware/hdmi/IHdmiCecListener.aidl \
+	core/java/android/hardware/hdmi/IHdmiCecService.aidl \
 	core/java/android/hardware/input/IInputManager.aidl \
 	core/java/android/hardware/input/IInputDevicesChangedListener.aidl \
 	core/java/android/hardware/location/IFusedLocationHardware.aidl \
@@ -174,6 +178,7 @@
 	core/java/android/print/IWriteResultCallback.aidl \
 	core/java/android/printservice/IPrintService.aidl \
 	core/java/android/printservice/IPrintServiceClient.aidl \
+	core/java/android/service/dreams/IDozeHardware.aidl \
 	core/java/android/service/dreams/IDreamManager.aidl \
 	core/java/android/service/dreams/IDreamService.aidl \
 	core/java/android/service/wallpaper/IWallpaperConnection.aidl \
diff --git a/CleanSpec.mk b/CleanSpec.mk
index cfa8be9..ef3f4ae 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -184,7 +184,7 @@
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/media/audio/effects/)
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/framework-res_intermediates)
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/core/java/android/print/IPrintClient.*)
-
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/services_intermediates)
 # ************************************************
 # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
 # ************************************************
diff --git a/api/current.txt b/api/current.txt
index 9aea28a..144dbc0 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -32,6 +32,7 @@
     field public static final java.lang.String BLUETOOTH = "android.permission.BLUETOOTH";
     field public static final java.lang.String BLUETOOTH_ADMIN = "android.permission.BLUETOOTH_ADMIN";
     field public static final java.lang.String BLUETOOTH_PRIVILEGED = "android.permission.BLUETOOTH_PRIVILEGED";
+    field public static final java.lang.String BODY_SENSORS = "android.permission.BODY_SENSORS";
     field public static final java.lang.String BRICK = "android.permission.BRICK";
     field public static final java.lang.String BROADCAST_PACKAGE_REMOVED = "android.permission.BROADCAST_PACKAGE_REMOVED";
     field public static final java.lang.String BROADCAST_SMS = "android.permission.BROADCAST_SMS";
@@ -276,6 +277,7 @@
     field public static final int allContactsName = 16843468; // 0x10102cc
     field public static final int allowBackup = 16843392; // 0x1010280
     field public static final int allowClearUserData = 16842757; // 0x1010005
+    field public static final int allowEmbedded = 16843765; // 0x10103f5
     field public static final int allowParallelSyncs = 16843570; // 0x1010332
     field public static final int allowSingleTap = 16843353; // 0x1010259
     field public static final int allowTaskReparenting = 16843268; // 0x1010204
@@ -1221,6 +1223,7 @@
     field public static final int windowShowAnimation = 16842934; // 0x10100b6
     field public static final int windowShowWallpaper = 16843410; // 0x1010292
     field public static final int windowSoftInputMode = 16843307; // 0x101022b
+    field public static final int windowSwipeToDismiss = 16843763; // 0x10103f3
     field public static final int windowTitleBackgroundStyle = 16842844; // 0x101005c
     field public static final int windowTitleSize = 16842842; // 0x101005a
     field public static final int windowTitleStyle = 16842843; // 0x101005b
@@ -3941,6 +3944,7 @@
     field public static final int FLAG_FOREGROUND_SERVICE = 64; // 0x40
     field public static final deprecated int FLAG_HIGH_PRIORITY = 128; // 0x80
     field public static final int FLAG_INSISTENT = 4; // 0x4
+    field public static final int FLAG_LOCAL_ONLY = 256; // 0x100
     field public static final int FLAG_NO_CLEAR = 32; // 0x20
     field public static final int FLAG_ONGOING_EVENT = 2; // 0x2
     field public static final int FLAG_ONLY_ALERT_ONCE = 8; // 0x8
@@ -4007,7 +4011,9 @@
   public static class Notification.Builder {
     ctor public Notification.Builder(android.content.Context);
     method public android.app.Notification.Builder addAction(int, java.lang.CharSequence, android.app.PendingIntent);
+    method public android.app.Notification.Builder addExtras(android.os.Bundle);
     method public android.app.Notification build();
+    method public android.os.Bundle getExtras();
     method public deprecated android.app.Notification getNotification();
     method public android.app.Notification.Builder setAutoCancel(boolean);
     method public android.app.Notification.Builder setContent(android.widget.RemoteViews);
@@ -4021,6 +4027,7 @@
     method public android.app.Notification.Builder setFullScreenIntent(android.app.PendingIntent, boolean);
     method public android.app.Notification.Builder setLargeIcon(android.graphics.Bitmap);
     method public android.app.Notification.Builder setLights(int, int, int);
+    method public android.app.Notification.Builder setLocalOnly(boolean);
     method public android.app.Notification.Builder setNumber(int);
     method public android.app.Notification.Builder setOngoing(boolean);
     method public android.app.Notification.Builder setOnlyAlertOnce(boolean);
@@ -7072,6 +7079,7 @@
     ctor public ComponentInfo();
     ctor public ComponentInfo(android.content.pm.ComponentInfo);
     ctor protected ComponentInfo(android.os.Parcel);
+    method public final int getBannerResource();
     method public final int getIconResource();
     method public final int getLogoResource();
     method public boolean isEnabled();
@@ -7175,11 +7183,13 @@
     ctor protected PackageItemInfo(android.os.Parcel);
     method protected void dumpBack(android.util.Printer, java.lang.String);
     method protected void dumpFront(android.util.Printer, java.lang.String);
+    method public android.graphics.drawable.Drawable loadBanner(android.content.pm.PackageManager);
     method public android.graphics.drawable.Drawable loadIcon(android.content.pm.PackageManager);
     method public java.lang.CharSequence loadLabel(android.content.pm.PackageManager);
     method public android.graphics.drawable.Drawable loadLogo(android.content.pm.PackageManager);
     method public android.content.res.XmlResourceParser loadXmlMetaData(android.content.pm.PackageManager, java.lang.String);
     method public void writeToParcel(android.os.Parcel, int);
+    field public int banner;
     field public int icon;
     field public int labelRes;
     field public int logo;
@@ -7207,12 +7217,16 @@
     method public abstract void clearPackagePreferredActivities(java.lang.String);
     method public abstract java.lang.String[] currentToCanonicalPackageNames(java.lang.String[]);
     method public abstract void extendVerificationTimeout(int, int, long);
+    method public abstract android.graphics.drawable.Drawable getActivityBanner(android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public abstract android.graphics.drawable.Drawable getActivityBanner(android.content.Intent) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract android.graphics.drawable.Drawable getActivityIcon(android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract android.graphics.drawable.Drawable getActivityIcon(android.content.Intent) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract android.content.pm.ActivityInfo getActivityInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract android.graphics.drawable.Drawable getActivityLogo(android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract android.graphics.drawable.Drawable getActivityLogo(android.content.Intent) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract java.util.List<android.content.pm.PermissionGroupInfo> getAllPermissionGroups(int);
+    method public abstract android.graphics.drawable.Drawable getApplicationBanner(android.content.pm.ApplicationInfo);
+    method public abstract android.graphics.drawable.Drawable getApplicationBanner(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract int getApplicationEnabledSetting(java.lang.String);
     method public abstract android.graphics.drawable.Drawable getApplicationIcon(android.content.pm.ApplicationInfo);
     method public abstract android.graphics.drawable.Drawable getApplicationIcon(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -7277,11 +7291,13 @@
     field public static final java.lang.String EXTRA_VERIFICATION_RESULT = "android.content.pm.extra.VERIFICATION_RESULT";
     field public static final java.lang.String FEATURE_APP_WIDGETS = "android.software.app_widgets";
     field public static final java.lang.String FEATURE_AUDIO_LOW_LATENCY = "android.hardware.audio.low_latency";
+    field public static final java.lang.String FEATURE_BACKUP = "android.software.backup";
     field public static final java.lang.String FEATURE_BLUETOOTH = "android.hardware.bluetooth";
     field public static final java.lang.String FEATURE_BLUETOOTH_LE = "android.hardware.bluetooth_le";
     field public static final java.lang.String FEATURE_CAMERA = "android.hardware.camera";
     field public static final java.lang.String FEATURE_CAMERA_ANY = "android.hardware.camera.any";
     field public static final java.lang.String FEATURE_CAMERA_AUTOFOCUS = "android.hardware.camera.autofocus";
+    field public static final java.lang.String FEATURE_CAMERA_EXTERNAL = "android.hardware.camera.external";
     field public static final java.lang.String FEATURE_CAMERA_FLASH = "android.hardware.camera.flash";
     field public static final java.lang.String FEATURE_CAMERA_FRONT = "android.hardware.camera.front";
     field public static final java.lang.String FEATURE_CONSUMER_IR = "android.hardware.consumerir";
@@ -7298,12 +7314,14 @@
     field public static final java.lang.String FEATURE_MICROPHONE = "android.hardware.microphone";
     field public static final java.lang.String FEATURE_NFC = "android.hardware.nfc";
     field public static final java.lang.String FEATURE_NFC_HOST_CARD_EMULATION = "android.hardware.nfc.hce";
+    field public static final java.lang.String FEATURE_PRINTING = "android.software.print";
     field public static final java.lang.String FEATURE_SCREEN_LANDSCAPE = "android.hardware.screen.landscape";
     field public static final java.lang.String FEATURE_SCREEN_PORTRAIT = "android.hardware.screen.portrait";
     field public static final java.lang.String FEATURE_SENSOR_ACCELEROMETER = "android.hardware.sensor.accelerometer";
     field public static final java.lang.String FEATURE_SENSOR_BAROMETER = "android.hardware.sensor.barometer";
     field public static final java.lang.String FEATURE_SENSOR_COMPASS = "android.hardware.sensor.compass";
     field public static final java.lang.String FEATURE_SENSOR_GYROSCOPE = "android.hardware.sensor.gyroscope";
+    field public static final java.lang.String FEATURE_SENSOR_HEART_RATE = "android.hardware.sensor.heartrate";
     field public static final java.lang.String FEATURE_SENSOR_LIGHT = "android.hardware.sensor.light";
     field public static final java.lang.String FEATURE_SENSOR_PROXIMITY = "android.hardware.sensor.proximity";
     field public static final java.lang.String FEATURE_SENSOR_STEP_COUNTER = "android.hardware.sensor.stepcounter";
@@ -7320,6 +7338,7 @@
     field public static final java.lang.String FEATURE_TOUCHSCREEN_MULTITOUCH_JAZZHAND = "android.hardware.touchscreen.multitouch.jazzhand";
     field public static final java.lang.String FEATURE_USB_ACCESSORY = "android.hardware.usb.accessory";
     field public static final java.lang.String FEATURE_USB_HOST = "android.hardware.usb.host";
+    field public static final java.lang.String FEATURE_WATCH = "android.hardware.type.watch";
     field public static final java.lang.String FEATURE_WIFI = "android.hardware.wifi";
     field public static final java.lang.String FEATURE_WIFI_DIRECT = "android.hardware.wifi.direct";
     field public static final int GET_ACTIVITIES = 1; // 0x1
@@ -7642,6 +7661,7 @@
     field public static final int UI_MODE_TYPE_NORMAL = 1; // 0x1
     field public static final int UI_MODE_TYPE_TELEVISION = 4; // 0x4
     field public static final int UI_MODE_TYPE_UNDEFINED = 0; // 0x0
+    field public static final int UI_MODE_TYPE_WATCH = 6; // 0x6
     field public int densityDpi;
     field public float fontScale;
     field public int hardKeyboardHidden;
@@ -10716,9 +10736,31 @@
     method public java.lang.String getName();
     method public float getPower();
     method public float getResolution();
+    method public java.lang.String getStringType();
     method public int getType();
     method public java.lang.String getVendor();
     method public int getVersion();
+    field public static final java.lang.String STRING_TYPE_ACCELEROMETER = "android.sensor.accelerometer";
+    field public static final java.lang.String STRING_TYPE_AMBIENT_TEMPERATURE = "android.sensor.ambient_temperature";
+    field public static final java.lang.String STRING_TYPE_GAME_ROTATION_VECTOR = "android.sensor.game_rotation_vector";
+    field public static final java.lang.String STRING_TYPE_GEOMAGNETIC_ROTATION_VECTOR = "android.sensor.geomagnetic_rotation_vector";
+    field public static final java.lang.String STRING_TYPE_GRAVITY = "android.sensor.gravity";
+    field public static final java.lang.String STRING_TYPE_GYROSCOPE = "android.sensor.gyroscope";
+    field public static final java.lang.String STRING_TYPE_GYROSCOPE_UNCALIBRATED = "android.sensor.gyroscope_uncalibrated";
+    field public static final java.lang.String STRING_TYPE_HEART_RATE = "android.sensor.heart_rate";
+    field public static final java.lang.String STRING_TYPE_LIGHT = "android.sensor.light";
+    field public static final java.lang.String STRING_TYPE_LINEAR_ACCELERATION = "android.sensor.linear_acceleration";
+    field public static final java.lang.String STRING_TYPE_MAGNETIC_FIELD = "android.sensor.magnetic_field";
+    field public static final java.lang.String STRING_TYPE_MAGNETIC_FIELD_UNCALIBRATED = "android.sensor.magnetic_field_uncalibrated";
+    field public static final deprecated java.lang.String STRING_TYPE_ORIENTATION = "android.sensor.orientation";
+    field public static final java.lang.String STRING_TYPE_PRESSURE = "android.sensor.pressure";
+    field public static final java.lang.String STRING_TYPE_PROXIMITY = "android.sensor.proximity";
+    field public static final java.lang.String STRING_TYPE_RELATIVE_HUMIDITY = "android.sensor.relative_humidity";
+    field public static final java.lang.String STRING_TYPE_ROTATION_VECTOR = "android.sensor.rotation_vector";
+    field public static final java.lang.String STRING_TYPE_SIGNIFICANT_MOTION = "android.sensor.significant_motion";
+    field public static final java.lang.String STRING_TYPE_STEP_COUNTER = "android.sensor.step_counter";
+    field public static final java.lang.String STRING_TYPE_STEP_DETECTOR = "android.sensor.step_detector";
+    field public static final deprecated java.lang.String STRING_TYPE_TEMPERATURE = "android.sensor.temperature";
     field public static final int TYPE_ACCELEROMETER = 1; // 0x1
     field public static final int TYPE_ALL = -1; // 0xffffffff
     field public static final int TYPE_AMBIENT_TEMPERATURE = 13; // 0xd
@@ -10727,6 +10769,7 @@
     field public static final int TYPE_GRAVITY = 9; // 0x9
     field public static final int TYPE_GYROSCOPE = 4; // 0x4
     field public static final int TYPE_GYROSCOPE_UNCALIBRATED = 16; // 0x10
+    field public static final int TYPE_HEART_RATE = 21; // 0x15
     field public static final int TYPE_LIGHT = 5; // 0x5
     field public static final int TYPE_LINEAR_ACCELERATION = 10; // 0xa
     field public static final int TYPE_MAGNETIC_FIELD = 2; // 0x2
@@ -10870,6 +10913,7 @@
     method public void registerDisplayListener(android.hardware.display.DisplayManager.DisplayListener, android.os.Handler);
     method public void unregisterDisplayListener(android.hardware.display.DisplayManager.DisplayListener);
     field public static final java.lang.String DISPLAY_CATEGORY_PRESENTATION = "android.hardware.display.category.PRESENTATION";
+    field public static final int VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY = 8; // 0x8
     field public static final int VIRTUAL_DISPLAY_FLAG_PRESENTATION = 2; // 0x2
     field public static final int VIRTUAL_DISPLAY_FLAG_PUBLIC = 1; // 0x1
     field public static final int VIRTUAL_DISPLAY_FLAG_SECURE = 4; // 0x4
@@ -10883,7 +10927,9 @@
 
   public final class VirtualDisplay {
     method public android.view.Display getDisplay();
+    method public android.view.Surface getSurface();
     method public void release();
+    method public void setSurface(android.view.Surface);
   }
 
 }
@@ -11027,10 +11073,7 @@
     method public int getDeviceSubclass();
     method public android.hardware.usb.UsbInterface getInterface(int);
     method public int getInterfaceCount();
-    method public java.lang.String getManufacturerName();
     method public int getProductId();
-    method public java.lang.String getProductName();
-    method public java.lang.String getSerialNumber();
     method public int getVendorId();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator CREATOR;
@@ -17464,6 +17507,7 @@
     field public static final int JELLY_BEAN_MR1 = 17; // 0x11
     field public static final int JELLY_BEAN_MR2 = 18; // 0x12
     field public static final int KITKAT = 19; // 0x13
+    field public static final int KITKAT_WATCH = 20; // 0x14
   }
 
   public final class Bundle implements java.lang.Cloneable android.os.Parcelable {
@@ -17651,7 +17695,6 @@
     method public static void startMethodTracing(java.lang.String);
     method public static void startMethodTracing(java.lang.String, int);
     method public static void startMethodTracing(java.lang.String, int, int);
-    method public static void startMethodTracingSampling(java.lang.String, int, int);
     method public static void startNativeTracing();
     method public static deprecated void stopAllocCounting();
     method public static void stopMethodTracing();
@@ -18148,7 +18191,8 @@
 
   public final class PowerManager {
     method public void goToSleep(long);
-    method public boolean isScreenOn();
+    method public boolean isInteractive();
+    method public deprecated boolean isScreenOn();
     method public android.os.PowerManager.WakeLock newWakeLock(int, java.lang.String);
     method public void reboot(java.lang.String);
     method public void userActivity(long, boolean);
@@ -21794,7 +21838,7 @@
   }
 
   public class BaseObj {
-    method public synchronized void destroy();
+    method public void destroy();
     method public java.lang.String getName();
     method public void setName(java.lang.String);
   }
@@ -22485,6 +22529,15 @@
     method public void setRed(int, int);
   }
 
+  public final class ScriptIntrinsicResize extends android.renderscript.ScriptIntrinsic {
+    method public static android.renderscript.ScriptIntrinsicResize create(android.renderscript.RenderScript);
+    method public void forEach_bicubic(android.renderscript.Allocation);
+    method public void forEach_bicubic(android.renderscript.Allocation, android.renderscript.Script.LaunchOptions);
+    method public android.renderscript.Script.FieldID getFieldID_Input();
+    method public android.renderscript.Script.KernelID getKernelID_bicubic();
+    method public void setInput(android.renderscript.Allocation);
+  }
+
   public final class ScriptIntrinsicYuvToRGB extends android.renderscript.ScriptIntrinsic {
     method public static android.renderscript.ScriptIntrinsicYuvToRGB create(android.renderscript.RenderScript, android.renderscript.Element);
     method public void forEach(android.renderscript.Allocation);
@@ -22731,6 +22784,7 @@
     method public android.service.notification.StatusBarNotification clone();
     method public int describeContents();
     method public int getId();
+    method public java.lang.String getKey();
     method public android.app.Notification getNotification();
     method public java.lang.String getPackageName();
     method public long getPostTime();
@@ -24060,12 +24114,16 @@
     method public void clearPackagePreferredActivities(java.lang.String);
     method public java.lang.String[] currentToCanonicalPackageNames(java.lang.String[]);
     method public void extendVerificationTimeout(int, int, long);
+    method public android.graphics.drawable.Drawable getActivityBanner(android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public android.graphics.drawable.Drawable getActivityBanner(android.content.Intent) throws android.content.pm.PackageManager.NameNotFoundException;
     method public android.graphics.drawable.Drawable getActivityIcon(android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
     method public android.graphics.drawable.Drawable getActivityIcon(android.content.Intent) throws android.content.pm.PackageManager.NameNotFoundException;
     method public android.content.pm.ActivityInfo getActivityInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public android.graphics.drawable.Drawable getActivityLogo(android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
     method public android.graphics.drawable.Drawable getActivityLogo(android.content.Intent) throws android.content.pm.PackageManager.NameNotFoundException;
     method public java.util.List<android.content.pm.PermissionGroupInfo> getAllPermissionGroups(int);
+    method public android.graphics.drawable.Drawable getApplicationBanner(android.content.pm.ApplicationInfo);
+    method public android.graphics.drawable.Drawable getApplicationBanner(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public int getApplicationEnabledSetting(java.lang.String);
     method public android.graphics.drawable.Drawable getApplicationIcon(android.content.pm.ApplicationInfo);
     method public android.graphics.drawable.Drawable getApplicationIcon(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -26178,7 +26236,6 @@
     method public final java.lang.CharSequence coerceToString();
     method public static final java.lang.String coerceToString(int, int);
     method public static float complexToDimension(int, android.util.DisplayMetrics);
-    method public static float complexToDimensionNoisy(int, android.util.DisplayMetrics);
     method public static int complexToDimensionPixelOffset(int, android.util.DisplayMetrics);
     method public static int complexToDimensionPixelSize(int, android.util.DisplayMetrics);
     method public static float complexToFloat(int);
@@ -26363,6 +26420,7 @@
     method public float getRefreshRate();
     method public int getRotation();
     method public void getSize(android.graphics.Point);
+    method public int getState();
     method public deprecated int getWidth();
     method public boolean isValid();
     field public static final int DEFAULT_DISPLAY = 0; // 0x0
@@ -26370,6 +26428,10 @@
     field public static final int FLAG_PRIVATE = 4; // 0x4
     field public static final int FLAG_SECURE = 2; // 0x2
     field public static final int FLAG_SUPPORTS_PROTECTED_BUFFERS = 1; // 0x1
+    field public static final int STATE_DOZING = 3; // 0x3
+    field public static final int STATE_OFF = 1; // 0x1
+    field public static final int STATE_ON = 2; // 0x2
+    field public static final int STATE_UNKNOWN = 0; // 0x0
   }
 
   public class DragEvent implements android.os.Parcelable {
@@ -26701,7 +26763,7 @@
     field public static final int FLAG_SOFT_KEYBOARD = 2; // 0x2
     field public static final int FLAG_TRACKING = 512; // 0x200
     field public static final int FLAG_VIRTUAL_HARD_KEY = 64; // 0x40
-    field public static final int FLAG_WOKE_HERE = 1; // 0x1
+    field public static final deprecated int FLAG_WOKE_HERE = 1; // 0x1
     field public static final int KEYCODE_0 = 7; // 0x7
     field public static final int KEYCODE_1 = 8; // 0x8
     field public static final int KEYCODE_2 = 9; // 0x9
@@ -26896,6 +26958,7 @@
     field public static final int KEYCODE_SHIFT_LEFT = 59; // 0x3b
     field public static final int KEYCODE_SHIFT_RIGHT = 60; // 0x3c
     field public static final int KEYCODE_SLASH = 76; // 0x4c
+    field public static final int KEYCODE_SLEEP = 223; // 0xdf
     field public static final int KEYCODE_SOFT_LEFT = 1; // 0x1
     field public static final int KEYCODE_SOFT_RIGHT = 2; // 0x2
     field public static final int KEYCODE_SPACE = 62; // 0x3e
@@ -26917,6 +26980,7 @@
     field public static final int KEYCODE_VOLUME_MUTE = 164; // 0xa4
     field public static final int KEYCODE_VOLUME_UP = 24; // 0x18
     field public static final int KEYCODE_W = 51; // 0x33
+    field public static final int KEYCODE_WAKEUP = 224; // 0xe0
     field public static final int KEYCODE_WINDOW = 171; // 0xab
     field public static final int KEYCODE_X = 52; // 0x34
     field public static final int KEYCODE_Y = 53; // 0x35
@@ -27528,6 +27592,7 @@
     method public android.view.accessibility.AccessibilityNodeInfo createAccessibilityNodeInfo();
     method public void createContextMenu(android.view.ContextMenu);
     method public void destroyDrawingCache();
+    method public android.view.WindowInsets dispatchApplyWindowInsets(android.view.WindowInsets);
     method public void dispatchConfigurationChanged(android.content.res.Configuration);
     method public void dispatchDisplayHint(int);
     method public boolean dispatchDragEvent(android.view.DragEvent);
@@ -27559,7 +27624,7 @@
     method public final android.view.View findViewById(int);
     method public final android.view.View findViewWithTag(java.lang.Object);
     method public void findViewsWithText(java.util.ArrayList<android.view.View>, java.lang.CharSequence, int);
-    method protected boolean fitSystemWindows(android.graphics.Rect);
+    method protected deprecated boolean fitSystemWindows(android.graphics.Rect);
     method public android.view.View focusSearch(int);
     method public void forceLayout();
     method public static int generateViewId();
@@ -27741,6 +27806,7 @@
     method public void offsetTopAndBottom(int);
     method protected void onAnimationEnd();
     method protected void onAnimationStart();
+    method public android.view.WindowInsets onApplyWindowInsets(android.view.WindowInsets);
     method protected void onAttachedToWindow();
     method public void onCancelPendingInputEvents();
     method public boolean onCheckIsTextEditor();
@@ -27807,7 +27873,8 @@
     method public boolean removeCallbacks(java.lang.Runnable);
     method public void removeOnAttachStateChangeListener(android.view.View.OnAttachStateChangeListener);
     method public void removeOnLayoutChangeListener(android.view.View.OnLayoutChangeListener);
-    method public void requestFitSystemWindows();
+    method public void requestApplyInsets();
+    method public deprecated void requestFitSystemWindows();
     method public final boolean requestFocus();
     method public final boolean requestFocus(int);
     method public boolean requestFocus(int, android.graphics.Rect);
@@ -27871,6 +27938,7 @@
     method public void setNextFocusLeftId(int);
     method public void setNextFocusRightId(int);
     method public void setNextFocusUpId(int);
+    method public void setOnApplyWindowInsetsListener(android.view.View.OnApplyWindowInsetsListener);
     method public void setOnClickListener(android.view.View.OnClickListener);
     method public void setOnCreateContextMenuListener(android.view.View.OnCreateContextMenuListener);
     method public void setOnDragListener(android.view.View.OnDragListener);
@@ -28089,6 +28157,10 @@
     field public static final int UNSPECIFIED = 0; // 0x0
   }
 
+  public static abstract interface View.OnApplyWindowInsetsListener {
+    method public abstract android.view.WindowInsets onApplyWindowInsets(android.view.View, android.view.WindowInsets);
+  }
+
   public static abstract interface View.OnAttachStateChangeListener {
     method public abstract void onViewAttachedToWindow(android.view.View);
     method public abstract void onViewDetachedFromWindow(android.view.View);
@@ -28144,7 +28216,7 @@
     method public static int getDoubleTapTimeout();
     method public static deprecated int getEdgeSlop();
     method public static deprecated int getFadingEdgeLength();
-    method public static long getGlobalActionKeyTimeout();
+    method public static deprecated long getGlobalActionKeyTimeout();
     method public static int getJumpTapTimeout();
     method public static int getKeyRepeatDelay();
     method public static int getKeyRepeatTimeout();
@@ -28646,6 +28718,7 @@
     field public static final int FEATURE_OPTIONS_PANEL = 0; // 0x0
     field public static final int FEATURE_PROGRESS = 2; // 0x2
     field public static final int FEATURE_RIGHT_ICON = 4; // 0x4
+    field public static final int FEATURE_SWIPE_TO_DISMISS = 11; // 0xb
     field public static final int ID_ANDROID_CONTENT = 16908290; // 0x1020002
     field public static final int PROGRESS_END = 10000; // 0x2710
     field public static final int PROGRESS_INDETERMINATE_OFF = -4; // 0xfffffffc
@@ -28696,6 +28769,19 @@
     method public abstract void onFocusLost(android.view.WindowId);
   }
 
+  public final class WindowInsets {
+    ctor public WindowInsets(android.view.WindowInsets);
+    method public android.view.WindowInsets consumeSystemWindowInsets();
+    method public int getSystemWindowInsetBottom();
+    method public int getSystemWindowInsetLeft();
+    method public int getSystemWindowInsetRight();
+    method public int getSystemWindowInsetTop();
+    method public boolean hasInsets();
+    method public boolean hasSystemWindowInsets();
+    method public boolean isRound();
+    method public android.view.WindowInsets replaceSystemWindowInsets(int, int, int, int);
+  }
+
   public abstract interface WindowManager implements android.view.ViewManager {
     method public abstract android.view.Display getDefaultDisplay();
     method public abstract void removeViewImmediate(android.view.View);
@@ -28761,7 +28847,7 @@
     field public static final int FLAG_SHOW_WALLPAPER = 1048576; // 0x100000
     field public static final int FLAG_SHOW_WHEN_LOCKED = 524288; // 0x80000
     field public static final int FLAG_SPLIT_TOUCH = 8388608; // 0x800000
-    field public static final int FLAG_TOUCHABLE_WHEN_WAKING = 64; // 0x40
+    field public static final deprecated int FLAG_TOUCHABLE_WHEN_WAKING = 64; // 0x40
     field public static final int FLAG_TRANSLUCENT_NAVIGATION = 134217728; // 0x8000000
     field public static final int FLAG_TRANSLUCENT_STATUS = 67108864; // 0x4000000
     field public static final int FLAG_TURN_SCREEN_ON = 2097152; // 0x200000
@@ -42723,11 +42809,11 @@
   }
 
   public class ConcurrentHashMap extends java.util.AbstractMap implements java.util.concurrent.ConcurrentMap java.io.Serializable {
-    ctor public ConcurrentHashMap(int, float, int);
-    ctor public ConcurrentHashMap(int, float);
-    ctor public ConcurrentHashMap(int);
     ctor public ConcurrentHashMap();
+    ctor public ConcurrentHashMap(int);
     ctor public ConcurrentHashMap(java.util.Map<? extends K, ? extends V>);
+    ctor public ConcurrentHashMap(int, float);
+    ctor public ConcurrentHashMap(int, float, int);
     method public boolean contains(java.lang.Object);
     method public java.util.Enumeration<V> elements();
     method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
@@ -44167,12 +44253,12 @@
   public final class Matcher implements java.util.regex.MatchResult {
     method public java.util.regex.Matcher appendReplacement(java.lang.StringBuffer, java.lang.String);
     method public java.lang.StringBuffer appendTail(java.lang.StringBuffer);
-    method public int end(int);
     method public int end();
+    method public int end(int);
     method public boolean find(int);
     method public boolean find();
-    method public java.lang.String group(int);
     method public java.lang.String group();
+    method public java.lang.String group(int);
     method public int groupCount();
     method public boolean hasAnchoringBounds();
     method public boolean hasTransparentBounds();
@@ -44189,8 +44275,8 @@
     method public boolean requireEnd();
     method public java.util.regex.Matcher reset();
     method public java.util.regex.Matcher reset(java.lang.CharSequence);
-    method public int start(int) throws java.lang.IllegalStateException;
     method public int start();
+    method public int start(int) throws java.lang.IllegalStateException;
     method public java.util.regex.MatchResult toMatchResult();
     method public java.util.regex.Matcher useAnchoringBounds(boolean);
     method public java.util.regex.Matcher usePattern(java.util.regex.Pattern);
@@ -50931,7 +51017,7 @@
     method public java.lang.String getString(java.lang.String) throws org.json.JSONException;
     method public boolean has(java.lang.String);
     method public boolean isNull(java.lang.String);
-    method public java.util.Iterator keys();
+    method public java.util.Iterator<java.lang.String> keys();
     method public int length();
     method public org.json.JSONArray names();
     method public static java.lang.String numberToString(java.lang.Number) throws org.json.JSONException;
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 0344d26..89e15d2 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -19,8 +19,9 @@
 package com.android.commands.am;
 
 import android.app.ActivityManager;
-import android.app.ActivityManager.StackBoxInfo;
+import android.app.ActivityManager.StackInfo;
 import android.app.ActivityManagerNative;
+import android.app.IActivityContainer;
 import android.app.IActivityController;
 import android.app.IActivityManager;
 import android.app.IInstrumentationWatcher;
@@ -31,9 +32,11 @@
 import android.content.Intent;
 import android.content.pm.IPackageManager;
 import android.content.pm.ResolveInfo;
+import android.graphics.Rect;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Bundle;
+import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -106,11 +109,11 @@
                 "       am to-intent-uri [INTENT]\n" +
                 "       am switch-user <USER_ID>\n" +
                 "       am stop-user <USER_ID>\n" +
-                "       am stack create <TASK_ID> <RELATIVE_STACK_BOX_ID> <POSITION> <WEIGHT>\n" +
+                "       am stack start <DISPLAY_ID> <INTENT>\n" +
                 "       am stack movetask <TASK_ID> <STACK_ID> [true|false]\n" +
-                "       am stack resize <STACK_ID> <WEIGHT>\n" +
-                "       am stack boxes\n" +
-                "       am stack box <STACK_BOX_ID>\n" +
+                "       am stack resize <STACK_ID> <LEFT,TOP,RIGHT,BOTTOM>\n" +
+                "       am stack list\n" +
+                "       am stack info <STACK_ID>\n" +
                 "\n" +
                 "am start: start an Activity.  Options are:\n" +
                 "    -D: enable debugging\n" +
@@ -204,24 +207,16 @@
                 "am stop-user: stop execution of USER_ID, not allowing it to run any\n" +
                 "  code until a later explicit switch to it.\n" +
                 "\n" +
-                "am stack create: create a new stack relative to an existing one.\n" +
-                "   <TASK_ID>: the task to populate the new stack with. Must exist.\n" +
-                "   <RELATIVE_STACK_BOX_ID>: existing stack box's id.\n" +
-                "   <POSITION>: 0: before <RELATIVE_STACK_BOX_ID>, per RTL/LTR configuration,\n" +
-                "               1: after <RELATIVE_STACK_BOX_ID>, per RTL/LTR configuration,\n" +
-                "               2: to left of <RELATIVE_STACK_BOX_ID>,\n" +
-                "               3: to right of <RELATIVE_STACK_BOX_ID>," +
-                "               4: above <RELATIVE_STACK_BOX_ID>, 5: below <RELATIVE_STACK_BOX_ID>\n" +
-                "   <WEIGHT>: float between 0.2 and 0.8 inclusive.\n" +
+                "am stack start: start a new activity on <DISPLAY_ID> using <INTENT>.\n" +
                 "\n" +
                 "am stack movetask: move <TASK_ID> from its current stack to the top (true) or" +
                 "   bottom (false) of <STACK_ID>.\n" +
                 "\n" +
-                "am stack resize: change <STACK_ID> relative size to new <WEIGHT>.\n" +
+                "am stack resize: change <STACK_ID> size and position to <LEFT,TOP,RIGHT,BOTTOM>.\n" +
                 "\n" +
-                "am stack boxes: list the hierarchy of stack boxes and their contents.\n" +
+                "am stack list: list all of the activity stacks and their sizes.\n" +
                 "\n" +
-                "am stack box: list the hierarchy of stack boxes rooted at <STACK_BOX_ID>.\n" +
+                "am stack info: display the information about activity stack <STACK_ID>.\n" +
                 "\n" +
                 "<INTENT> specifications include these flags and arguments:\n" +
                 "    [-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>]\n" +
@@ -1546,35 +1541,32 @@
 
     private void runStack() throws Exception {
         String op = nextArgRequired();
-        if (op.equals("create")) {
-            runStackCreate();
+        if (op.equals("start")) {
+            runStackStart();
         } else if (op.equals("movetask")) {
             runStackMoveTask();
         } else if (op.equals("resize")) {
-            runStackBoxResize();
-        } else if (op.equals("boxes")) {
-            runStackBoxes();
-        } else if (op.equals("box")) {
-            runStackBoxInfo();
+            runStackResize();
+        } else if (op.equals("list")) {
+            runStackList();
+        } else if (op.equals("info")) {
+            runStackInfo();
         } else {
             showError("Error: unknown command '" + op + "'");
             return;
         }
     }
 
-    private void runStackCreate() throws Exception {
-        String taskIdStr = nextArgRequired();
-        int taskId = Integer.valueOf(taskIdStr);
-        String relativeToStr = nextArgRequired();
-        int relativeTo = Integer.valueOf(relativeToStr);
-        String positionStr = nextArgRequired();
-        int position = Integer.valueOf(positionStr);
-        String weightStr = nextArgRequired();
-        float weight = Float.valueOf(weightStr);
+    private void runStackStart() throws Exception {
+        String displayIdStr = nextArgRequired();
+        int displayId = Integer.valueOf(displayIdStr);
+        Intent intent = makeIntent(UserHandle.USER_CURRENT);
 
         try {
-            int stackId = mAm.createStack(taskId, relativeTo, position, weight);
-            System.out.println("createStack returned new stackId=" + stackId + "\n\n");
+            IBinder homeActivityToken = mAm.getHomeActivityToken();
+            IActivityContainer container = mAm.createActivityContainer(homeActivityToken, null);
+            container.attachToDisplay(displayId);
+            container.startActivity(intent);
         } catch (RemoteException e) {
         }
     }
@@ -1601,34 +1593,40 @@
         }
     }
 
-    private void runStackBoxResize() throws Exception {
-        String stackBoxIdStr = nextArgRequired();
-        int stackBoxId = Integer.valueOf(stackBoxIdStr);
-        String weightStr = nextArgRequired();
-        float weight = Float.valueOf(weightStr);
+    private void runStackResize() throws Exception {
+        String stackIdStr = nextArgRequired();
+        int stackId = Integer.valueOf(stackIdStr);
+        String leftStr = nextArgRequired();
+        int left = Integer.valueOf(leftStr);
+        String topStr = nextArgRequired();
+        int top = Integer.valueOf(topStr);
+        String rightStr = nextArgRequired();
+        int right = Integer.valueOf(rightStr);
+        String bottomStr = nextArgRequired();
+        int bottom = Integer.valueOf(bottomStr);
 
         try {
-            mAm.resizeStackBox(stackBoxId, weight);
+            mAm.resizeStack(stackId, new Rect(left, top, right, bottom));
         } catch (RemoteException e) {
         }
     }
 
-    private void runStackBoxes() throws Exception {
+    private void runStackList() throws Exception {
         try {
-            List<StackBoxInfo> stackBoxes = mAm.getStackBoxes();
-            for (StackBoxInfo info : stackBoxes) {
+            List<StackInfo> stacks = mAm.getAllStackInfos();
+            for (StackInfo info : stacks) {
                 System.out.println(info);
             }
         } catch (RemoteException e) {
         }
     }
 
-    private void runStackBoxInfo() throws Exception {
+    private void runStackInfo() throws Exception {
         try {
-            String stackBoxIdStr = nextArgRequired();
-            int stackBoxId = Integer.valueOf(stackBoxIdStr);
-            StackBoxInfo stackBoxInfo = mAm.getStackBoxInfo(stackBoxId); 
-            System.out.println(stackBoxInfo);
+            String stackIdStr = nextArgRequired();
+            int stackId = Integer.valueOf(stackIdStr);
+            StackInfo info = mAm.getStackInfo(stackId);
+            System.out.println(info);
         } catch (RemoteException e) {
         }
     }
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 10ef535..e8b3bb9c 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -645,7 +645,8 @@
 public class Activity extends ContextThemeWrapper
         implements LayoutInflater.Factory2,
         Window.Callback, KeyEvent.Callback,
-        OnCreateContextMenuListener, ComponentCallbacks2 {
+        OnCreateContextMenuListener, ComponentCallbacks2,
+        Window.OnWindowDismissedCallback {
     private static final String TAG = "Activity";
     private static final boolean DEBUG_LIFECYCLE = false;
 
@@ -2402,6 +2403,15 @@
         }
         return false;
     }
+
+    /**
+     * Called when the main window associated with the activity has been dismissed.
+     * @hide
+     */
+    @Override
+    public void onWindowDismissed() {
+        finish();
+    }
     
     /**
      * Called to process key events.  You can override this to intercept all 
@@ -5189,6 +5199,7 @@
         
         mWindow = PolicyManager.makeNewWindow(this);
         mWindow.setCallback(this);
+        mWindow.setOnWindowDismissedCallback(this);
         mWindow.getLayoutInflater().setPrivateFactory(this);
         if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
             mWindow.setSoftInputMode(info.softInputMode);
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 7ca3459..c877cd3 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -1289,106 +1289,15 @@
     }
 
     /**
-     * Information you can retrieve about the WindowManager StackBox hierarchy.
-     * @hide
-     */
-    public static class StackBoxInfo implements Parcelable {
-        public int stackBoxId;
-        public float weight;
-        public boolean vertical;
-        public Rect bounds;
-        public StackBoxInfo[] children;
-        public int stackId;
-        public StackInfo stack;
-
-        @Override
-        public int describeContents() {
-            return 0;
-        }
-
-        @Override
-        public void writeToParcel(Parcel dest, int flags) {
-            dest.writeInt(stackBoxId);
-            dest.writeFloat(weight);
-            dest.writeInt(vertical ? 1 : 0);
-            bounds.writeToParcel(dest, flags);
-            dest.writeInt(stackId);
-            if (children != null) {
-                children[0].writeToParcel(dest, flags);
-                children[1].writeToParcel(dest, flags);
-            } else {
-                stack.writeToParcel(dest, flags);
-            }
-        }
-
-        public void readFromParcel(Parcel source) {
-            stackBoxId = source.readInt();
-            weight = source.readFloat();
-            vertical = source.readInt() == 1;
-            bounds = Rect.CREATOR.createFromParcel(source);
-            stackId = source.readInt();
-            if (stackId == -1) {
-                children = new StackBoxInfo[2];
-                children[0] = StackBoxInfo.CREATOR.createFromParcel(source);
-                children[1] = StackBoxInfo.CREATOR.createFromParcel(source);
-            } else {
-                stack = StackInfo.CREATOR.createFromParcel(source);
-            }
-        }
-
-        public static final Creator<StackBoxInfo> CREATOR =
-                new Creator<ActivityManager.StackBoxInfo>() {
-
-            @Override
-            public StackBoxInfo createFromParcel(Parcel source) {
-                return new StackBoxInfo(source);
-            }
-
-            @Override
-            public StackBoxInfo[] newArray(int size) {
-                return new StackBoxInfo[size];
-            }
-        };
-
-        public StackBoxInfo() {
-        }
-
-        public StackBoxInfo(Parcel source) {
-            readFromParcel(source);
-        }
-
-        public String toString(String prefix) {
-            StringBuilder sb = new StringBuilder(256);
-            sb.append(prefix); sb.append("Box id=" + stackBoxId); sb.append(" weight=" + weight);
-            sb.append(" vertical=" + vertical); sb.append(" bounds=" + bounds.toShortString());
-            sb.append("\n");
-            if (children != null) {
-                sb.append(prefix); sb.append("First child=\n");
-                sb.append(children[0].toString(prefix + "  "));
-                sb.append(prefix); sb.append("Second child=\n");
-                sb.append(children[1].toString(prefix + "  "));
-            } else {
-                sb.append(prefix); sb.append("Stack=\n");
-                sb.append(stack.toString(prefix + "  "));
-            }
-            return sb.toString();
-        }
-
-        @Override
-        public String toString() {
-            return toString("");
-        }
-    }
-
-    /**
      * Information you can retrieve about an ActivityStack in the system.
      * @hide
      */
     public static class StackInfo implements Parcelable {
         public int stackId;
-        public Rect bounds;
+        public Rect bounds = new Rect();
         public int[] taskIds;
         public String[] taskNames;
+        public int displayId;
 
         @Override
         public int describeContents() {
@@ -1404,6 +1313,7 @@
             dest.writeInt(bounds.bottom);
             dest.writeIntArray(taskIds);
             dest.writeStringArray(taskNames);
+            dest.writeInt(displayId);
         }
 
         public void readFromParcel(Parcel source) {
@@ -1412,6 +1322,7 @@
                     source.readInt(), source.readInt(), source.readInt(), source.readInt());
             taskIds = source.createIntArray();
             taskNames = source.createStringArray();
+            displayId = source.readInt();
         }
 
         public static final Creator<StackInfo> CREATOR = new Creator<StackInfo>() {
@@ -1435,7 +1346,9 @@
         public String toString(String prefix) {
             StringBuilder sb = new StringBuilder(256);
             sb.append(prefix); sb.append("Stack id="); sb.append(stackId);
-                    sb.append(" bounds="); sb.append(bounds.toShortString()); sb.append("\n");
+                    sb.append(" bounds="); sb.append(bounds.toShortString());
+                    sb.append(" displayId="); sb.append(displayId);
+                    sb.append("\n");
             prefix = prefix + "  ";
             for (int i = 0; i < taskIds.length; ++i) {
                 sb.append(prefix); sb.append("taskId="); sb.append(taskIds[i]);
diff --git a/services/java/com/android/server/power/DisplayBlanker.java b/core/java/android/app/ActivityManagerInternal.java
similarity index 62%
copy from services/java/com/android/server/power/DisplayBlanker.java
copy to core/java/android/app/ActivityManagerInternal.java
index 6072053..5262a5f 100644
--- a/services/java/com/android/server/power/DisplayBlanker.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 The Android Open Source Project
+ * Copyright (C) 2014 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,12 +14,15 @@
  * limitations under the License.
  */
 
-package com.android.server.power;
+package android.app;
 
 /**
- * Blanks or unblanks all displays.
+ * Activity manager local system service interface.
+ *
+ * @hide Only for use within the system server.
  */
-interface DisplayBlanker {
-    public void blankAllDisplays();
-    public void unblankAllDisplays();
+public abstract class ActivityManagerInternal {
+    // Called by the power manager.
+    public abstract void goingToSleep();
+    public abstract void wakingUp();
 }
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 74266cc..14c495f 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -16,7 +16,7 @@
 
 package android.app;
 
-import android.app.ActivityManager.StackBoxInfo;
+import android.app.ActivityManager.StackInfo;
 import android.content.ComponentName;
 import android.content.IIntentReceiver;
 import android.content.IIntentSender;
@@ -31,6 +31,7 @@
 import android.content.pm.UserInfo;
 import android.content.res.Configuration;
 import android.graphics.Bitmap;
+import android.graphics.Rect;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Bundle;
@@ -611,18 +612,6 @@
             return true;
         }
 
-        case CREATE_STACK_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            int taskId = data.readInt();
-            int relativeStackId = data.readInt();
-            int position = data.readInt();
-            float weight = data.readFloat();
-            int res = createStack(taskId, relativeStackId, position, weight);
-            reply.writeNoException();
-            reply.writeInt(res);
-            return true;
-        }
-
         case MOVE_TASK_TO_STACK_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             int taskId = data.readInt();
@@ -635,25 +624,26 @@
 
         case RESIZE_STACK_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
-            int stackBoxId = data.readInt();
+            int stackId = data.readInt();
             float weight = data.readFloat();
-            resizeStackBox(stackBoxId, weight);
+            Rect r = Rect.CREATOR.createFromParcel(data);
+            resizeStack(stackId, r);
             reply.writeNoException();
             return true;
         }
 
-        case GET_STACK_BOXES_TRANSACTION: {
+        case GET_ALL_STACK_INFOS_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
-            List<StackBoxInfo> list = getStackBoxes();
+            List<StackInfo> list = getAllStackInfos();
             reply.writeNoException();
             reply.writeTypedList(list);
             return true;
         }
 
-        case GET_STACK_BOX_INFO_TRANSACTION: {
+        case GET_STACK_INFO_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
-            int stackBoxId = data.readInt();
-            StackBoxInfo info = getStackBoxInfo(stackBoxId);
+            int stackId = data.readInt();
+            StackInfo info = getStackInfo(stackId);
             reply.writeNoException();
             if (info != null) {
                 reply.writeInt(1);
@@ -1209,20 +1199,6 @@
             return true;
         }
 
-        case GOING_TO_SLEEP_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            goingToSleep();
-            reply.writeNoException();
-            return true;
-        }
-
-        case WAKING_UP_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            wakingUp();
-            reply.writeNoException();
-            return true;
-        }
-
         case SET_LOCK_SCREEN_SHOWN_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             setLockScreenShown(data.readInt() != 0);
@@ -1293,17 +1269,6 @@
             return true;
         }
 
-        case START_RUNNING_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            String pkg = data.readString();
-            String cls = data.readString();
-            String action = data.readString();
-            String indata = data.readString();
-            startRunning(pkg, cls, action, indata);
-            reply.writeNoException();
-            return true;
-        }
-
         case HANDLE_APPLICATION_CRASH_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             IBinder app = data.readStrongBinder();
@@ -2028,6 +1993,54 @@
             reply.writeNoException();
             return true;
         }
+
+        case CREATE_ACTIVITY_CONTAINER_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            IBinder parentActivityToken = data.readStrongBinder();
+            IActivityContainerCallback callback =
+                    IActivityContainerCallback.Stub.asInterface(data.readStrongBinder());
+            IActivityContainer activityContainer =
+                    createActivityContainer(parentActivityToken, callback);
+            reply.writeNoException();
+            if (activityContainer != null) {
+                reply.writeInt(1);
+                reply.writeStrongBinder(activityContainer.asBinder());
+            } else {
+                reply.writeInt(0);
+            }
+            return true;
+        }
+
+        case DELETE_ACTIVITY_CONTAINER_TRANSACTION:  {
+            data.enforceInterface(IActivityManager.descriptor);
+            IActivityContainer activityContainer =
+                    IActivityContainer.Stub.asInterface(data.readStrongBinder());
+            deleteActivityContainer(activityContainer);
+            reply.writeNoException();
+            return true;
+        }
+
+        case GET_ACTIVITY_CONTAINER_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            IBinder activityToken = data.readStrongBinder();
+            IActivityContainer activityContainer = getEnclosingActivityContainer(activityToken);
+            reply.writeNoException();
+            if (activityContainer != null) {
+                reply.writeInt(1);
+                reply.writeStrongBinder(activityContainer.asBinder());
+            } else {
+                reply.writeInt(0);
+            }
+            return true;
+        }
+
+        case GET_HOME_ACTIVITY_TOKEN_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            IBinder homeActivityToken = getHomeActivityToken();
+            reply.writeNoException();
+            reply.writeStrongBinder(homeActivityToken);
+            return true;
+        }
         }
 
         return super.onTransact(code, data, reply, flags);
@@ -2715,24 +2728,6 @@
         reply.recycle();
     }
     @Override
-    public int createStack(int taskId, int relativeStackBoxId, int position, float weight)
-            throws RemoteException
-    {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeInt(taskId);
-        data.writeInt(relativeStackBoxId);
-        data.writeInt(position);
-        data.writeFloat(weight);
-        mRemote.transact(CREATE_STACK_TRANSACTION, data, reply, 0);
-        reply.readException();
-        int res = reply.readInt();
-        data.recycle();
-        reply.recycle();
-        return res;
-    }
-    @Override
     public void moveTaskToStack(int taskId, int stackId, boolean toTop) throws RemoteException
     {
         Parcel data = Parcel.obtain();
@@ -2747,44 +2742,44 @@
         reply.recycle();
     }
     @Override
-    public void resizeStackBox(int stackBoxId, float weight) throws RemoteException
+    public void resizeStack(int stackBoxId, Rect r) throws RemoteException
     {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
         data.writeInt(stackBoxId);
-        data.writeFloat(weight);
+        r.writeToParcel(data, 0);
         mRemote.transact(RESIZE_STACK_TRANSACTION, data, reply, IBinder.FLAG_ONEWAY);
         reply.readException();
         data.recycle();
         reply.recycle();
     }
     @Override
-    public List<StackBoxInfo> getStackBoxes() throws RemoteException
+    public List<StackInfo> getAllStackInfos() throws RemoteException
     {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
-        mRemote.transact(GET_STACK_BOXES_TRANSACTION, data, reply, 0);
+        mRemote.transact(GET_ALL_STACK_INFOS_TRANSACTION, data, reply, 0);
         reply.readException();
-        ArrayList<StackBoxInfo> list = reply.createTypedArrayList(StackBoxInfo.CREATOR);
+        ArrayList<StackInfo> list = reply.createTypedArrayList(StackInfo.CREATOR);
         data.recycle();
         reply.recycle();
         return list;
     }
     @Override
-    public StackBoxInfo getStackBoxInfo(int stackBoxId) throws RemoteException
+    public StackInfo getStackInfo(int stackId) throws RemoteException
     {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeInt(stackBoxId);
-        mRemote.transact(GET_STACK_BOX_INFO_TRANSACTION, data, reply, 0);
+        data.writeInt(stackId);
+        mRemote.transact(GET_STACK_INFO_TRANSACTION, data, reply, 0);
         reply.readException();
         int res = reply.readInt();
-        StackBoxInfo info = null;
+        StackInfo info = null;
         if (res != 0) {
-            info = StackBoxInfo.CREATOR.createFromParcel(reply);
+            info = StackInfo.CREATOR.createFromParcel(reply);
         }
         data.recycle();
         reply.recycle();
@@ -3566,26 +3561,6 @@
         reply.recycle();
         return pfd;
     }
-    public void goingToSleep() throws RemoteException
-    {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        mRemote.transact(GOING_TO_SLEEP_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-    public void wakingUp() throws RemoteException
-    {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        mRemote.transact(WAKING_UP_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
     public void setLockScreenShown(boolean shown) throws RemoteException
     {
         Parcel data = Parcel.obtain();
@@ -3673,20 +3648,6 @@
         reply.recycle();
         return res;
     }
-    public void startRunning(String pkg, String cls, String action,
-            String indata) throws RemoteException {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeString(pkg);
-        data.writeString(cls);
-        data.writeString(action);
-        data.writeString(indata);
-        mRemote.transact(START_RUNNING_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
     public boolean testIsSystemReady()
     {
         /* this base class version is never called */
@@ -4660,5 +4621,70 @@
         reply.recycle();
     }
 
+    public IActivityContainer createActivityContainer(IBinder parentActivityToken,
+            IActivityContainerCallback callback) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeStrongBinder(parentActivityToken);
+        data.writeStrongBinder(callback == null ? null : callback.asBinder());
+        mRemote.transact(CREATE_ACTIVITY_CONTAINER_TRANSACTION, data, reply, 0);
+        reply.readException();
+        final int result = reply.readInt();
+        final IActivityContainer res;
+        if (result == 1) {
+            res = IActivityContainer.Stub.asInterface(reply.readStrongBinder());
+        } else {
+            res = null;
+        }
+        data.recycle();
+        reply.recycle();
+        return res;
+    }
+
+    public void deleteActivityContainer(IActivityContainer activityContainer)
+            throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeStrongBinder(activityContainer.asBinder());
+        mRemote.transact(DELETE_ACTIVITY_CONTAINER_TRANSACTION, data, reply, 0);
+        reply.readException();
+        data.recycle();
+        reply.recycle();
+    }
+
+    public IActivityContainer getEnclosingActivityContainer(IBinder activityToken)
+            throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeStrongBinder(activityToken);
+        mRemote.transact(GET_ACTIVITY_CONTAINER_TRANSACTION, data, reply, 0);
+        reply.readException();
+        final int result = reply.readInt();
+        final IActivityContainer res;
+        if (result == 1) {
+            res = IActivityContainer.Stub.asInterface(reply.readStrongBinder());
+        } else {
+            res = null;
+        }
+        data.recycle();
+        reply.recycle();
+        return res;
+    }
+
+    public IBinder getHomeActivityToken() throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        mRemote.transact(GET_HOME_ACTIVITY_TOKEN_TRANSACTION, data, reply, 0);
+        reply.readException();
+        IBinder res = reply.readStrongBinder();
+        data.recycle();
+        reply.recycle();
+        return res;
+    }
+
     private IBinder mRemote;
 }
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 9a3478e..7f8dbba 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -2249,15 +2249,27 @@
             final Activity activity) {
         ContextImpl appContext = ContextImpl.createActivityContext(this, r.packageInfo, r.token);
         appContext.setOuterContext(activity);
+        Context baseContext = appContext;
+
+        final DisplayManagerGlobal dm = DisplayManagerGlobal.getInstance();
+        try {
+            IActivityContainer container =
+                    ActivityManagerNative.getDefault().getEnclosingActivityContainer(r.token);
+            final int displayId =
+                    container == null ? Display.DEFAULT_DISPLAY : container.getDisplayId();
+            if (displayId > Display.DEFAULT_DISPLAY) {
+                Display display = dm.getRealDisplay(displayId, r.token);
+                baseContext = appContext.createDisplayContext(display);
+            }
+        } catch (RemoteException e) {
+        }
 
         // For debugging purposes, if the activity's package name contains the value of
         // the "debug.use-second-display" system property as a substring, then show
         // its content on a secondary display if there is one.
-        Context baseContext = appContext;
         String pkgName = SystemProperties.get("debug.second-display.pkg");
         if (pkgName != null && !pkgName.isEmpty()
                 && r.packageInfo.mPackageName.contains(pkgName)) {
-            DisplayManagerGlobal dm = DisplayManagerGlobal.getInstance();
             for (int displayId : dm.getDisplayIds()) {
                 if (displayId != Display.DEFAULT_DISPLAY) {
                     Display display = dm.getRealDisplay(displayId, r.token);
diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java
new file mode 100644
index 0000000..097c64e
--- /dev/null
+++ b/core/java/android/app/ActivityView.java
@@ -0,0 +1,413 @@
+/*
+ * 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.app;
+
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.IIntentSender;
+import android.content.Intent;
+import android.content.IntentSender;
+import android.graphics.SurfaceTexture;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.AttributeSet;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.view.InputDevice;
+import android.view.InputEvent;
+import android.view.MotionEvent;
+import android.view.Surface;
+import android.view.TextureView;
+import android.view.TextureView.SurfaceTextureListener;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import dalvik.system.CloseGuard;
+
+import java.lang.ref.WeakReference;
+
+/** @hide */
+public class ActivityView extends ViewGroup {
+    private static final String TAG = "ActivityView";
+    private static final boolean DEBUG = false;
+
+    DisplayMetrics mMetrics;
+    private final TextureView mTextureView;
+    private ActivityContainerWrapper mActivityContainer;
+    private Activity mActivity;
+    private int mWidth;
+    private int mHeight;
+    private Surface mSurface;
+    private int mLastVisibility;
+
+    // Only one IIntentSender or Intent may be queued at a time. Most recent one wins.
+    IIntentSender mQueuedPendingIntent;
+    Intent mQueuedIntent;
+
+    public ActivityView(Context context) {
+        this(context, null);
+    }
+
+    public ActivityView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public ActivityView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+
+        while (context instanceof ContextWrapper) {
+            if (context instanceof Activity) {
+                mActivity = (Activity)context;
+                break;
+            }
+            context = ((ContextWrapper)context).getBaseContext();
+        }
+        if (mActivity == null) {
+            throw new IllegalStateException("The ActivityView's Context is not an Activity.");
+        }
+
+        try {
+            mActivityContainer = new ActivityContainerWrapper(
+                    ActivityManagerNative.getDefault().createActivityContainer(
+                            mActivity.getActivityToken(), new ActivityContainerCallback(this)));
+        } catch (RemoteException e) {
+            throw new RuntimeException("ActivityView: Unable to create ActivityContainer. "
+                    + e);
+        }
+
+        mTextureView = new TextureView(context);
+        mTextureView.setSurfaceTextureListener(new ActivityViewSurfaceTextureListener());
+        addView(mTextureView);
+
+        WindowManager wm = (WindowManager)mActivity.getSystemService(Context.WINDOW_SERVICE);
+        mMetrics = new DisplayMetrics();
+        wm.getDefaultDisplay().getMetrics(mMetrics);
+
+        mLastVisibility = getVisibility();
+
+        if (DEBUG) Log.v(TAG, "ctor()");
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        mTextureView.layout(0, 0, r - l, b - t);
+    }
+
+    @Override
+    protected void onVisibilityChanged(View changedView, int visibility) {
+        super.onVisibilityChanged(changedView, visibility);
+
+        if (mSurface != null) {
+            try {
+                if (visibility == View.GONE) {
+                    mActivityContainer.setSurface(null, mWidth, mHeight, mMetrics.densityDpi);
+                } else if (mLastVisibility == View.GONE) {
+                    // Don't change surface when going between View.VISIBLE and View.INVISIBLE.
+                    mActivityContainer.setSurface(mSurface, mWidth, mHeight, mMetrics.densityDpi);
+                }
+            } catch (RemoteException e) {
+                throw new RuntimeException(
+                        "ActivityView: Unable to set surface of ActivityContainer. " + e);
+            }
+        }
+        mLastVisibility = visibility;
+    }
+
+    private boolean injectInputEvent(InputEvent event) {
+        return mActivityContainer != null && mActivityContainer.injectEvent(event);
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        return injectInputEvent(event) || super.onTouchEvent(event);
+    }
+
+    @Override
+    public boolean onGenericMotionEvent(MotionEvent event) {
+        if (event.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) {
+            if (injectInputEvent(event)) {
+                return true;
+            }
+        }
+        return super.onGenericMotionEvent(event);
+    }
+
+    @Override
+    public void onAttachedToWindow() {
+        if (DEBUG) Log.v(TAG, "onAttachedToWindow(): mActivityContainer=" + mActivityContainer +
+                " mSurface=" + mSurface);
+    }
+
+    @Override
+    public void onDetachedFromWindow() {
+        if (DEBUG) Log.v(TAG, "onDetachedFromWindow(): mActivityContainer=" + mActivityContainer +
+                " mSurface=" + mSurface);
+    }
+
+    public boolean isAttachedToDisplay() {
+        return mSurface != null;
+    }
+
+    public void startActivity(Intent intent) {
+        if (mActivityContainer == null) {
+            throw new IllegalStateException("Attempt to call startActivity after release");
+        }
+        if (DEBUG) Log.v(TAG, "startActivity(): intent=" + intent + " " +
+                (isAttachedToDisplay() ? "" : "not") + " attached");
+        if (mSurface != null) {
+            mActivityContainer.startActivity(intent);
+        } else {
+            mActivityContainer.checkEmbeddedAllowed(intent);
+            mQueuedIntent = intent;
+            mQueuedPendingIntent = null;
+        }
+    }
+
+    public void startActivity(IntentSender intentSender) {
+        if (mActivityContainer == null) {
+            throw new IllegalStateException("Attempt to call startActivity after release");
+        }
+        if (DEBUG) Log.v(TAG, "startActivityIntentSender(): intentSender=" + intentSender + " " +
+                (isAttachedToDisplay() ? "" : "not") + " attached");
+        final IIntentSender iIntentSender = intentSender.getTarget();
+        if (mSurface != null) {
+            mActivityContainer.startActivityIntentSender(iIntentSender);
+        } else {
+            mActivityContainer.checkEmbeddedAllowedIntentSender(iIntentSender);
+            mQueuedPendingIntent = iIntentSender;
+            mQueuedIntent = null;
+        }
+    }
+
+    public void startActivity(PendingIntent pendingIntent) {
+        if (mActivityContainer == null) {
+            throw new IllegalStateException("Attempt to call startActivity after release");
+        }
+        if (DEBUG) Log.v(TAG, "startActivityPendingIntent(): PendingIntent=" + pendingIntent + " "
+                + (isAttachedToDisplay() ? "" : "not") + " attached");
+        final IIntentSender iIntentSender = pendingIntent.getTarget();
+        if (mSurface != null) {
+            mActivityContainer.startActivityIntentSender(iIntentSender);
+        } else {
+            mActivityContainer.checkEmbeddedAllowedIntentSender(iIntentSender);
+            mQueuedPendingIntent = iIntentSender;
+            mQueuedIntent = null;
+        }
+    }
+
+    public void release() {
+        if (DEBUG) Log.v(TAG, "release() mActivityContainer=" + mActivityContainer +
+                " mSurface=" + mSurface);
+        if (mActivityContainer == null) {
+            Log.e(TAG, "Duplicate call to release");
+            return;
+        }
+        mActivityContainer.release();
+        mActivityContainer = null;
+
+        if (mSurface != null) {
+            mSurface.release();
+            mSurface = null;
+        }
+
+        mTextureView.setSurfaceTextureListener(null);
+    }
+
+    private void attachToSurfaceWhenReady() {
+        final SurfaceTexture surfaceTexture = mTextureView.getSurfaceTexture();
+        if (surfaceTexture == null || mSurface != null) {
+            // Either not ready to attach, or already attached.
+            return;
+        }
+
+        mSurface = new Surface(surfaceTexture);
+        try {
+            mActivityContainer.setSurface(mSurface, mWidth, mHeight, mMetrics.densityDpi);
+        } catch (RemoteException e) {
+            mSurface.release();
+            mSurface = null;
+            throw new RuntimeException("ActivityView: Unable to create ActivityContainer. " + e);
+        }
+
+        if (DEBUG) Log.v(TAG, "attachToSurfaceWhenReady: " + (mQueuedIntent != null ||
+                mQueuedPendingIntent != null ? "" : "no") + " queued intent");
+        if (mQueuedIntent != null) {
+            mActivityContainer.startActivity(mQueuedIntent);
+            mQueuedIntent = null;
+        } else if (mQueuedPendingIntent != null) {
+            mActivityContainer.startActivityIntentSender(mQueuedPendingIntent);
+            mQueuedPendingIntent = null;
+        }
+    }
+
+    private class ActivityViewSurfaceTextureListener implements SurfaceTextureListener {
+        @Override
+        public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width,
+                int height) {
+            if (mActivityContainer == null) {
+                return;
+            }
+            if (DEBUG) Log.d(TAG, "onSurfaceTextureAvailable: width=" + width + " height="
+                    + height);
+            mWidth = width;
+            mHeight = height;
+            attachToSurfaceWhenReady();
+        }
+
+        @Override
+        public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int width,
+                int height) {
+            if (mActivityContainer == null) {
+                return;
+            }
+            if (DEBUG) Log.d(TAG, "onSurfaceTextureSizeChanged: w=" + width + " h=" + height);
+        }
+
+        @Override
+        public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
+            if (mActivityContainer == null) {
+                return true;
+            }
+            if (DEBUG) Log.d(TAG, "onSurfaceTextureDestroyed");
+            mSurface.release();
+            mSurface = null;
+            try {
+                mActivityContainer.setSurface(null, mWidth, mHeight, mMetrics.densityDpi);
+            } catch (RemoteException e) {
+                throw new RuntimeException(
+                        "ActivityView: Unable to set surface of ActivityContainer. " + e);
+            }
+            return true;
+        }
+
+        @Override
+        public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {
+//            Log.d(TAG, "onSurfaceTextureUpdated");
+        }
+
+    }
+
+    private static class ActivityContainerCallback extends IActivityContainerCallback.Stub {
+        private final WeakReference<ActivityView> mActivityViewWeakReference;
+
+        ActivityContainerCallback(ActivityView activityView) {
+            mActivityViewWeakReference = new WeakReference<ActivityView>(activityView);
+        }
+
+        @Override
+        public void setVisible(IBinder container, boolean visible) {
+            if (DEBUG) Log.v(TAG, "setVisible(): container=" + container + " visible=" + visible +
+                    " ActivityView=" + mActivityViewWeakReference.get());
+        }
+    }
+
+    private static class ActivityContainerWrapper {
+        private final IActivityContainer mIActivityContainer;
+        private final CloseGuard mGuard = CloseGuard.get();
+
+        ActivityContainerWrapper(IActivityContainer container) {
+            mIActivityContainer = container;
+            mGuard.open("release");
+        }
+
+        void attachToDisplay(int displayId) {
+            try {
+                mIActivityContainer.attachToDisplay(displayId);
+            } catch (RemoteException e) {
+            }
+        }
+
+        void setSurface(Surface surface, int width, int height, int density)
+                throws RemoteException {
+            mIActivityContainer.setSurface(surface, width, height, density);
+        }
+
+        int startActivity(Intent intent) {
+            try {
+                return mIActivityContainer.startActivity(intent);
+            } catch (RemoteException e) {
+                throw new RuntimeException("ActivityView: Unable to startActivity. " + e);
+            }
+        }
+
+        int startActivityIntentSender(IIntentSender intentSender) {
+            try {
+                return mIActivityContainer.startActivityIntentSender(intentSender);
+            } catch (RemoteException e) {
+                throw new RuntimeException(
+                        "ActivityView: Unable to startActivity from IntentSender. " + e);
+            }
+        }
+
+        void checkEmbeddedAllowed(Intent intent) {
+            try {
+                mIActivityContainer.checkEmbeddedAllowed(intent);
+            } catch (RemoteException e) {
+                throw new RuntimeException(
+                        "ActivityView: Unable to startActivity from Intent. " + e);
+            }
+        }
+
+        void checkEmbeddedAllowedIntentSender(IIntentSender intentSender) {
+            try {
+                mIActivityContainer.checkEmbeddedAllowedIntentSender(intentSender);
+            } catch (RemoteException e) {
+                throw new RuntimeException(
+                        "ActivityView: Unable to startActivity from IntentSender. " + e);
+            }
+        }
+
+        int getDisplayId() {
+            try {
+                return mIActivityContainer.getDisplayId();
+            } catch (RemoteException e) {
+                return -1;
+            }
+        }
+
+        boolean injectEvent(InputEvent event) {
+            try {
+                return mIActivityContainer.injectEvent(event);
+            } catch (RemoteException e) {
+                return false;
+            }
+        }
+
+        void release() {
+            if (DEBUG) Log.v(TAG, "ActivityContainerWrapper: release called");
+            try {
+                mIActivityContainer.release();
+                mGuard.close();
+            } catch (RemoteException e) {
+            }
+        }
+
+        @Override
+        protected void finalize() throws Throwable {
+            if (DEBUG) Log.v(TAG, "ActivityContainerWrapper: finalize called");
+            try {
+                if (mGuard != null) {
+                    mGuard.warnIfOpen();
+                    release();
+                }
+            } finally {
+                super.finalize();
+            }
+        }
+
+    }
+}
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index a280448..02192eb 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -128,6 +128,25 @@
         return intent;
     }
 
+    /** @hide */
+    @Override
+    public Intent getLeanbackLaunchIntentForPackage(String packageName) {
+        // Try to find a main leanback_launcher activity.
+        Intent intentToResolve = new Intent(Intent.ACTION_MAIN);
+        intentToResolve.addCategory(Intent.CATEGORY_LEANBACK_LAUNCHER);
+        intentToResolve.setPackage(packageName);
+        List<ResolveInfo> ris = queryIntentActivities(intentToResolve, 0);
+
+        if (ris == null || ris.size() <= 0) {
+            return null;
+        }
+        Intent intent = new Intent(intentToResolve);
+        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        intent.setClassName(ris.get(0).activityInfo.packageName,
+                ris.get(0).activityInfo.name);
+        return intent;
+    }
+
     @Override
     public int[] getPackageGids(String packageName)
             throws NameNotFoundException {
@@ -729,6 +748,39 @@
     }
 
     @Override
+    public Drawable getActivityBanner(ComponentName activityName)
+            throws NameNotFoundException {
+        return getActivityInfo(activityName, 0).loadBanner(this);
+    }
+
+    @Override
+    public Drawable getActivityBanner(Intent intent)
+            throws NameNotFoundException {
+        if (intent.getComponent() != null) {
+            return getActivityBanner(intent.getComponent());
+        }
+
+        ResolveInfo info = resolveActivity(
+                intent, PackageManager.MATCH_DEFAULT_ONLY);
+        if (info != null) {
+            return info.activityInfo.loadBanner(this);
+        }
+
+        throw new NameNotFoundException(intent.toUri(0));
+    }
+
+    @Override
+    public Drawable getApplicationBanner(ApplicationInfo info) {
+        return info.loadBanner(this);
+    }
+
+    @Override
+    public Drawable getApplicationBanner(String packageName)
+            throws NameNotFoundException {
+        return getApplicationBanner(getApplicationInfo(packageName, 0));
+    }
+
+    @Override
     public Drawable getActivityLogo(ComponentName activityName)
             throws NameNotFoundException {
         return getActivityInfo(activityName, 0).loadLogo(this);
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index df50989..924d656 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -51,6 +51,8 @@
 import android.hardware.ISerialManager;
 import android.hardware.SerialManager;
 import android.hardware.SystemSensorManager;
+import android.hardware.hdmi.HdmiCecManager;
+import android.hardware.hdmi.IHdmiCecService;
 import android.hardware.camera2.CameraManager;
 import android.hardware.display.DisplayManager;
 import android.hardware.input.InputManager;
@@ -357,6 +359,13 @@
                     return new BluetoothManager(ctx);
                 }});
 
+        registerService(HDMI_CEC_SERVICE, new StaticServiceFetcher() {
+                public Object createStaticService() {
+                    IBinder b = ServiceManager.getService(HDMI_CEC_SERVICE);
+                    return new HdmiCecManager(IHdmiCecService.Stub.asInterface(b));
+                }});
+
+
         registerService(CLIPBOARD_SERVICE, new ServiceFetcher() {
                 public Object createService(ContextImpl ctx) {
                     return new ClipboardManager(ctx.getOuterContext(),
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index cda2c5f..7a362df 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -80,7 +80,7 @@
  * </div>
  */
 public class Dialog implements DialogInterface, Window.Callback,
-        KeyEvent.Callback, OnCreateContextMenuListener {
+        KeyEvent.Callback, OnCreateContextMenuListener, Window.OnWindowDismissedCallback {
     private static final String TAG = "Dialog";
     private Activity mOwnerActivity;
     
@@ -166,6 +166,7 @@
         Window w = PolicyManager.makeNewWindow(mContext);
         mWindow = w;
         w.setCallback(this);
+        w.setOnWindowDismissedCallback(this);
         w.setWindowManager(mWindowManager, null, null);
         w.setGravity(Gravity.CENTER);
         mListenersHandler = new ListenersHandler(this);
@@ -695,6 +696,12 @@
     
     public void onDetachedFromWindow() {
     }
+
+    /** @hide */
+    @Override
+    public void onWindowDismissed() {
+        dismiss();
+    }
     
     /**
      * Called to process key events.  You can override this to intercept all 
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index d626e5f..af8f177 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -1402,6 +1402,7 @@
         mRestored = false;
         mBackStackNesting = 0;
         mFragmentManager = null;
+        mChildFragmentManager = null;
         mActivity = null;
         mFragmentId = 0;
         mContainerId = 0;
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index bf2a629..76f9d97 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -1026,6 +1026,7 @@
                                     f.mActivity = null;
                                     f.mParentFragment = null;
                                     f.mFragmentManager = null;
+                                    f.mChildFragmentManager = null;
                                 }
                             }
                         }
diff --git a/core/java/android/app/IActivityContainer.aidl b/core/java/android/app/IActivityContainer.aidl
new file mode 100644
index 0000000..52884f7
--- /dev/null
+++ b/core/java/android/app/IActivityContainer.aidl
@@ -0,0 +1,37 @@
+/**
+ * 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.app;
+
+import android.app.IActivityContainerCallback;
+import android.content.Intent;
+import android.content.IIntentSender;
+import android.os.IBinder;
+import android.view.InputEvent;
+import android.view.Surface;
+
+/** @hide */
+interface IActivityContainer {
+    void attachToDisplay(int displayId);
+    void setSurface(in Surface surface, int width, int height, int density);
+    int startActivity(in Intent intent);
+    int startActivityIntentSender(in IIntentSender intentSender);
+    void checkEmbeddedAllowed(in Intent intent);
+    void checkEmbeddedAllowedIntentSender(in IIntentSender intentSender);
+    int getDisplayId();
+    boolean injectEvent(in InputEvent event);
+    void release();
+}
diff --git a/services/java/com/android/server/power/DisplayBlanker.java b/core/java/android/app/IActivityContainerCallback.aidl
similarity index 64%
copy from services/java/com/android/server/power/DisplayBlanker.java
copy to core/java/android/app/IActivityContainerCallback.aidl
index 6072053..7f6d2c3 100644
--- a/services/java/com/android/server/power/DisplayBlanker.java
+++ b/core/java/android/app/IActivityContainerCallback.aidl
@@ -1,11 +1,11 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
+/**
+ * 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
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,12 +14,11 @@
  * limitations under the License.
  */
 
-package com.android.server.power;
+package android.app;
 
-/**
- * Blanks or unblanks all displays.
- */
-interface DisplayBlanker {
-    public void blankAllDisplays();
-    public void unblankAllDisplays();
+import android.os.IBinder;
+
+/** @hide */
+interface IActivityContainerCallback {
+    oneway void setVisible(IBinder container, boolean visible);
 }
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 77c2ea0..4e2a57d 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -18,7 +18,7 @@
 
 import android.app.ActivityManager.RunningTaskInfo;
 import android.app.ActivityManager.RunningServiceInfo;
-import android.app.ActivityManager.StackBoxInfo;
+import android.app.ActivityManager.StackInfo;
 import android.content.ComponentName;
 import android.content.ContentProviderNative;
 import android.content.IContentProvider;
@@ -36,6 +36,7 @@
 import android.content.pm.UserInfo;
 import android.content.res.Configuration;
 import android.graphics.Bitmap;
+import android.graphics.Rect;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Debug;
@@ -117,12 +118,10 @@
     public void moveTaskToBack(int task) throws RemoteException;
     public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) throws RemoteException;
     public void moveTaskBackwards(int task) throws RemoteException;
-    public int createStack(int taskId, int relativeStackBoxId, int position, float weight)
-            throws RemoteException;
     public void moveTaskToStack(int taskId, int stackId, boolean toTop) throws RemoteException;
-    public void resizeStackBox(int stackBoxId, float weight) throws RemoteException;
-    public List<StackBoxInfo> getStackBoxes() throws RemoteException;
-    public StackBoxInfo getStackBoxInfo(int stackBoxId) throws RemoteException;
+    public void resizeStack(int stackId, Rect bounds) throws RemoteException;
+    public List<StackInfo> getAllStackInfos() throws RemoteException;
+    public StackInfo getStackInfo(int stackId) throws RemoteException;
     public void setFocusedStack(int stackId) throws RemoteException;
     public int getTaskForActivity(IBinder token, boolean onlyRoot) throws RemoteException;
     /* oneway */
@@ -229,8 +228,6 @@
     public void forceStopPackage(final String packageName, int userId) throws RemoteException;
     
     // Note: probably don't want to allow applications access to these.
-    public void goingToSleep() throws RemoteException;
-    public void wakingUp() throws RemoteException;
     public void setLockScreenShown(boolean shown) throws RemoteException;
 
     public void unhandledBack() throws RemoteException;
@@ -250,8 +247,6 @@
     public boolean killProcessesBelowForeground(String reason) throws RemoteException;
 
     // Special low-level communication with activity manager.
-    public void startRunning(String pkg, String cls, String action,
-            String data) throws RemoteException;
     public void handleApplicationCrash(IBinder app,
             ApplicationErrorReport.CrashInfo crashInfo) throws RemoteException;
     public boolean handleApplicationWtf(IBinder app, String tag,
@@ -408,6 +403,18 @@
 
     public void performIdleMaintenance() throws RemoteException;
 
+    /** @hide */
+    public IActivityContainer createActivityContainer(IBinder parentActivityToken,
+            IActivityContainerCallback callback) throws RemoteException;
+
+    /** @hide */
+    public void deleteActivityContainer(IActivityContainer container) throws RemoteException;
+
+    public IActivityContainer getEnclosingActivityContainer(IBinder activityToken)
+            throws RemoteException;
+
+    public IBinder getHomeActivityToken() throws RemoteException;
+
     /*
      * Private non-Binder interfaces
      */
@@ -514,7 +521,6 @@
 
     // Please keep these transaction codes the same -- they are also
     // sent by C++ code.
-    int START_RUNNING_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION;
     int HANDLE_APPLICATION_CRASH_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+1;
     int START_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+2;
     int UNHANDLED_BACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+3;
@@ -550,8 +556,6 @@
     int UNBIND_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+36;
     int PUBLISH_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+37;
     int ACTIVITY_RESUMED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+38;
-    int GOING_TO_SLEEP_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+39;
-    int WAKING_UP_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+40;
     int SET_DEBUG_APP_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+41;
     int SET_ALWAYS_FINISH_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+42;
     int START_INSTRUMENTATION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+43;
@@ -678,12 +682,12 @@
     int KILL_UID_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+164;
     int SET_USER_IS_MONKEY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+165;
     int HANG_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+166;
-    int CREATE_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+167;
+    int CREATE_ACTIVITY_CONTAINER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+167;
     int MOVE_TASK_TO_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+168;
     int RESIZE_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+169;
-    int GET_STACK_BOXES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+170;
+    int GET_ALL_STACK_INFOS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+170;
     int SET_FOCUSED_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+171;
-    int GET_STACK_BOX_INFO_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+172;
+    int GET_STACK_INFO_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+172;
     int CONVERT_FROM_TRANSLUCENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+173;
     int CONVERT_TO_TRANSLUCENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+174;
     int NOTIFY_ACTIVITY_DRAWN_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+175;
@@ -694,4 +698,7 @@
     int RELEASE_PERSISTABLE_URI_PERMISSION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+180;
     int GET_PERSISTED_URI_PERMISSIONS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+181;
     int APP_NOT_RESPONDING_VIA_PROVIDER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+182;
+    int GET_HOME_ACTIVITY_TOKEN_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+183;
+    int GET_ACTIVITY_CONTAINER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+184;
+    int DELETE_ACTIVITY_CONTAINER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+185;
 }
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 9f933ca..9911467 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -45,7 +45,8 @@
     void unregisterListener(in INotificationListener listener, int userid);
 
     void cancelNotificationFromListener(in INotificationListener token, String pkg, String tag, int id);
-    void cancelAllNotificationsFromListener(in INotificationListener token);
+    void cancelNotificationsFromListener(in INotificationListener token, in String[] keys);
 
-    StatusBarNotification[] getActiveNotificationsFromListener(in INotificationListener token);
+    StatusBarNotification[] getActiveNotificationsFromListener(in INotificationListener token, in String[] keys);
+    String[] getActiveNotificationKeysFromListener(in INotificationListener token);
 }
\ No newline at end of file
diff --git a/core/java/android/app/IWallpaperManager.aidl b/core/java/android/app/IWallpaperManager.aidl
index 3efd3c0..181eb63 100644
--- a/core/java/android/app/IWallpaperManager.aidl
+++ b/core/java/android/app/IWallpaperManager.aidl
@@ -71,4 +71,14 @@
      * Returns the desired minimum height for the wallpaper.
      */
     int getHeightHint();
+
+    /**
+     * Returns the name of the wallpaper. Private API.
+     */
+    String getName();
+
+    /**
+     * Informs the service that wallpaper settings have been restored. Private API.
+     */
+    void settingsRestored();
 }
diff --git a/core/java/android/app/LauncherActivity.java b/core/java/android/app/LauncherActivity.java
index 96c7246..9ec7f41 100644
--- a/core/java/android/app/LauncherActivity.java
+++ b/core/java/android/app/LauncherActivity.java
@@ -340,9 +340,11 @@
         super.onCreate(icicle);
         
         mPackageManager = getPackageManager();
-    
-        requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
-        setProgressBarIndeterminateVisibility(true);
+
+        if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_WATCH)) {
+            requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
+            setProgressBarIndeterminateVisibility(true);
+        }
         onSetContentView();
 
         mIconResizer = new IconResizer();
@@ -357,7 +359,9 @@
         updateAlertTitle();
         updateButtonText();
 
-        setProgressBarIndeterminateVisibility(false);
+        if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_WATCH)) {
+            setProgressBarIndeterminateVisibility(false);
+        }
     }
 
     private void updateAlertTitle() {
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index cce6fc4..298022e 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -314,8 +314,8 @@
 
     /**
      * Bit to be bitwise-ored into the {@link #flags} field that should be
-     * set if you want the sound and/or vibration play each time the
-     * notification is sent, even if it has not been canceled before that.
+     * set if you would only like the sound, vibrate and ticker to be played
+     * if the notification was not already showing.
      */
     public static final int FLAG_ONLY_ALERT_ONCE    = 0x00000008;
 
@@ -348,6 +348,13 @@
      */
     public static final int FLAG_HIGH_PRIORITY      = 0x00000080;
 
+    /**
+     * Bit to be bitswise-ored into the {@link #flags} field that should be
+     * set if this notification is relevant to the current device only
+     * and it is not recommended that it bridge to other devices.
+     */
+    public static final int FLAG_LOCAL_ONLY         = 0x00000100;
+
     public int flags;
 
     /**
@@ -394,41 +401,97 @@
     public int priority;
 
     /**
+     * Notification category: incoming call (voice or video) or similar synchronous communication request.
      * @hide
-     * Notification type: incoming call (voice or video) or similar synchronous communication request.
      */
-    public static final String KIND_CALL = "android.call";
+    public static final String CATEGORY_CALL = "call";
 
     /**
+     * Notification category: incoming direct message (SMS, instant message, etc.).
      * @hide
-     * Notification type: incoming direct message (SMS, instant message, etc.).
      */
-    public static final String KIND_MESSAGE = "android.message";
+    public static final String CATEGORY_MESSAGE = "msg";
 
     /**
+     * Notification category: asynchronous bulk message (email).
      * @hide
-     * Notification type: asynchronous bulk message (email).
      */
-    public static final String KIND_EMAIL = "android.email";
+    public static final String CATEGORY_EMAIL = "email";
 
     /**
+     * Notification category: calendar event.
      * @hide
-     * Notification type: calendar event.
      */
-    public static final String KIND_EVENT = "android.event";
+    public static final String CATEGORY_EVENT = "event";
 
     /**
+     * Notification category: promotion or advertisement.
      * @hide
-     * Notification type: promotion or advertisement.
      */
-    public static final String KIND_PROMO = "android.promo";
+    public static final String CATEGORY_PROMO = "promo";
 
     /**
+     * Notification category: alarm or timer.
      * @hide
-     * If this notification matches of one or more special types (see the <code>KIND_*</code>
-     * constants), add them here, best match first.
      */
-    public String[] kind;
+    public static final String CATEGORY_ALARM = "alarm";
+
+    /**
+     * Notification category: progress of a long-running background operation.
+     * @hide
+     */
+    public static final String CATEGORY_PROGRESS = "progress";
+
+    /**
+     * Notification category: social network or sharing update.
+     * @hide
+     */
+    public static final String CATEGORY_SOCIAL = "social";
+
+    /**
+     * Notification category: error in background operation or authentication status.
+     * @hide
+     */
+    public static final String CATEGORY_ERROR = "err";
+
+    /**
+     * Notification category: media transport control for playback.
+     * @hide
+     */
+    public static final String CATEGORY_TRANSPORT = "transport";
+
+    /**
+     * Notification category: system or device status update.  Reserved for system use.
+     * @hide
+     */
+    public static final String CATEGORY_SYSTEM = "sys";
+
+    /**
+     * Notification category: indication of running background service.
+     * @hide
+     */
+    public static final String CATEGORY_SERVICE = "service";
+
+    /**
+     * Notification category: a specific, timely recommendation for a single thing.
+     * For example, a news app might want to recommend a news story it believes the user will
+     * want to read next.
+     * @hide
+     */
+    public static final String CATEGORY_RECOMMENDATION = "recommendation";
+
+    /**
+     * Notification category: ongoing information about device or contextual status.
+     * @hide
+     */
+    public static final String CATEGORY_STATUS = "status";
+
+    /**
+     * One of the predefined notification categories (see the <code>CATEGORY_*</code> constants)
+     * that best describes this Notification.  May be used by the system for ranking and filtering.
+     * @hide
+     */
+    public String category;
 
     /**
      * Additional semantic data to be carried around with this Notification.
@@ -561,6 +624,13 @@
     public static final String EXTRA_AS_HEADS_UP = "headsup";
 
     /**
+     * Allow certain system-generated notifications to appear before the device is provisioned.
+     * Only available to notifications coming from the android package.
+     * @hide
+     */
+    public static final String EXTRA_ALLOW_DURING_SETUP = "android.allowDuringSetup";
+
+    /**
      * Value for {@link #EXTRA_AS_HEADS_UP}.
      * @hide
      */
@@ -750,7 +820,7 @@
 
         priority = parcel.readInt();
 
-        kind = parcel.createStringArray(); // may set kind to null
+        category = parcel.readString();
 
         extras = parcel.readBundle(); // may be null
 
@@ -815,12 +885,7 @@
 
         that.priority = this.priority;
 
-        final String[] thiskind = this.kind;
-        if (thiskind != null) {
-            final int N = thiskind.length;
-            final String[] thatkind = that.kind = new String[N];
-            System.arraycopy(thiskind, 0, thatkind, 0, N);
-        }
+        that.category = this.category;
 
         if (this.extras != null) {
             try {
@@ -957,7 +1022,7 @@
 
         parcel.writeInt(priority);
 
-        parcel.writeStringArray(kind); // ok for null
+        parcel.writeString(category);
 
         parcel.writeBundle(extras); // null ok
 
@@ -1077,16 +1142,7 @@
         sb.append(Integer.toHexString(this.defaults));
         sb.append(" flags=0x");
         sb.append(Integer.toHexString(this.flags));
-        sb.append(" kind=[");
-        if (this.kind == null) {
-            sb.append("null");
-        } else {
-            for (int i=0; i<this.kind.length; i++) {
-                if (i>0) sb.append(",");
-                sb.append(this.kind[i]);
-            }
-        }
-        sb.append("]");
+        sb.append(" category="); sb.append(this.category);
         if (actions != null) {
             sb.append(" ");
             sb.append(actions.length);
@@ -1165,7 +1221,7 @@
         private int mProgressMax;
         private int mProgress;
         private boolean mProgressIndeterminate;
-        private ArrayList<String> mKindList = new ArrayList<String>(1);
+        private String mCategory;
         private Bundle mExtras;
         private int mPriority;
         private ArrayList<Action> mActions = new ArrayList<Action>(MAX_ACTION_BUTTONS);
@@ -1532,6 +1588,17 @@
         }
 
         /**
+         * Set whether or not this notification should not bridge to other devices.
+         *
+         * <p>Some notifications can be bridged to other devices for remote display.
+         * This hint can be set to recommend this notification not be bridged.
+         */
+        public Builder setLocalOnly(boolean localOnly) {
+            setFlag(FLAG_LOCAL_ONLY, localOnly);
+            return this;
+        }
+
+        /**
          * Set which notification properties will be inherited from system defaults.
          * <p>
          * The value should be one or more of the following fields combined with
@@ -1556,24 +1623,42 @@
         }
 
         /**
+         * Set the notification category.
+         *
+         * @see Notification#category
          * @hide
-         *
-         * Add a kind (category) to this notification. Optional.
-         *
-         * @see Notification#kind
          */
-        public Builder addKind(String k) {
-            mKindList.add(k);
+        public Builder setCategory(String category) {
+            mCategory = category;
             return this;
         }
 
         /**
-         * Add metadata to this notification.
+         * Merge additional metadata into this notification.
          *
-         * A reference to the Bundle is held for the lifetime of this Builder, and the Bundle's
+         * <p>Values within the Bundle will replace existing extras values in this Builder.
+         *
+         * @see Notification#extras
+         */
+        public Builder addExtras(Bundle bag) {
+            if (mExtras == null) {
+                mExtras = new Bundle(bag);
+            } else {
+                mExtras.putAll(bag);
+            }
+            return this;
+        }
+
+        /**
+         * Set metadata for this notification.
+         *
+         * <p>A reference to the Bundle is held for the lifetime of this Builder, and the Bundle's
          * current contents are copied into the Notification each time {@link #build()} is
          * called.
          *
+         * <p>Replaces any existing extras values with those from the provided Bundle.
+         * Use {@link #addExtras} to merge in metadata instead.
+         *
          * @see Notification#extras
          */
         public Builder setExtras(Bundle bag) {
@@ -1582,6 +1667,23 @@
         }
 
         /**
+         * Get the current metadata Bundle used by this notification Builder.
+         *
+         * <p>The returned Bundle is shared with this Builder.
+         *
+         * <p>The current contents of this Bundle are copied into the Notification each time
+         * {@link #build()} is called.
+         *
+         * @see Notification#extras
+         */
+        public Bundle getExtras() {
+            if (mExtras == null) {
+                mExtras = new Bundle();
+            }
+            return mExtras;
+        }
+
+        /**
          * Add an action to this notification. Actions are typically displayed by
          * the system as a button adjacent to the notification content.
          * <p>
@@ -1819,12 +1921,7 @@
             if ((mDefaults & DEFAULT_LIGHTS) != 0) {
                 n.flags |= FLAG_SHOW_LIGHTS;
             }
-            if (mKindList.size() > 0) {
-                n.kind = new String[mKindList.size()];
-                mKindList.toArray(n.kind);
-            } else {
-                n.kind = null;
-            }
+            n.category = mCategory;
             n.priority = mPriority;
             if (mActions.size() > 0) {
                 n.actions = new Action[mActions.size()];
@@ -1839,7 +1936,7 @@
          * this Notification object.
          * @hide
          */
-        public void addExtras(Bundle extras) {
+        public void populateExtras(Bundle extras) {
             // Store original information used in the construction of this object
             extras.putCharSequence(EXTRA_TITLE, mContentTitle);
             extras.putCharSequence(EXTRA_TEXT, mContentText);
@@ -1877,7 +1974,7 @@
 
             n.extras = mExtras != null ? new Bundle(mExtras) : new Bundle();
 
-            addExtras(n.extras);
+            populateExtras(n.extras);
             if (mStyle != null) {
                 mStyle.addExtras(n.extras);
             }
@@ -1900,8 +1997,7 @@
      * An object that can apply a rich notification style to a {@link Notification.Builder}
      * object.
      */
-    public static abstract class Style
-    {
+    public static abstract class Style {
         private CharSequence mBigContentTitle;
         private CharSequence mSummaryText = null;
         private boolean mSummaryTextSet = false;
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index 45467b8..7129e9e 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -95,8 +95,8 @@
      */
     public static final int FLAG_ONE_SHOT = 1<<30;
     /**
-     * Flag indicating that if the described PendingIntent already
-     * exists, then simply return null instead of creating it.
+     * Flag indicating that if the described PendingIntent does not
+     * already exist, then simply return null instead of creating it.
      * For use with {@link #getActivity}, {@link #getBroadcast}, and
      * {@link #getService}.
      */
diff --git a/core/java/android/app/UiModeManager.java b/core/java/android/app/UiModeManager.java
index 0c22740..c6731c9 100644
--- a/core/java/android/app/UiModeManager.java
+++ b/core/java/android/app/UiModeManager.java
@@ -166,9 +166,11 @@
     /**
      * Return the current running mode type.  May be one of
      * {@link Configuration#UI_MODE_TYPE_NORMAL Configuration.UI_MODE_TYPE_NORMAL},
-     * {@link Configuration#UI_MODE_TYPE_DESK Configuration.UI_MODE_TYPE_DESK}, or
-     * {@link Configuration#UI_MODE_TYPE_CAR Configuration.UI_MODE_TYPE_CAR}, or
-     * {@link Configuration#UI_MODE_TYPE_TELEVISION Configuration.UI_MODE_TYPE_APPLIANCE}.
+     * {@link Configuration#UI_MODE_TYPE_DESK Configuration.UI_MODE_TYPE_DESK},
+     * {@link Configuration#UI_MODE_TYPE_CAR Configuration.UI_MODE_TYPE_CAR},
+     * {@link Configuration#UI_MODE_TYPE_TELEVISION Configuration.UI_MODE_TYPE_TELEVISION},
+     * {@link Configuration#UI_MODE_TYPE_APPLIANCE Configuration.UI_MODE_TYPE_APPLIANCE}, or
+     * {@link Configuration#UI_MODE_TYPE_WATCH Configuration.UI_MODE_TYPE_WATCH}.
      */
     public int getCurrentModeType() {
         if (mService != null) {
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 62f7147..3a766b7 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -283,13 +283,15 @@
         }
 
         private Bitmap getCurrentWallpaperLocked(Context context) {
+            if (mService == null) {
+                Log.w(TAG, "WallpaperService not running");
+                return null;
+            }
+
             try {
                 Bundle params = new Bundle();
                 ParcelFileDescriptor fd = mService.getWallpaper(this, params);
                 if (fd != null) {
-                    int width = params.getInt("width", 0);
-                    int height = params.getInt("height", 0);
-
                     try {
                         BitmapFactory.Options options = new BitmapFactory.Options();
                         return BitmapFactory.decodeFileDescriptor(
@@ -311,28 +313,21 @@
         }
         
         private Bitmap getDefaultWallpaperLocked(Context context) {
-            try {
-                InputStream is = context.getResources().openRawResource(
-                        com.android.internal.R.drawable.default_wallpaper);
-                if (is != null) {
-                    int width = mService.getWidthHint();
-                    int height = mService.getHeightHint();
-
+            InputStream is = context.getResources().openRawResource(
+                    com.android.internal.R.drawable.default_wallpaper);
+            if (is != null) {
+                try {
+                    BitmapFactory.Options options = new BitmapFactory.Options();
+                    return BitmapFactory.decodeStream(is, null, options);
+                } catch (OutOfMemoryError e) {
+                    Log.w(TAG, "Can't decode stream", e);
+                } finally {
                     try {
-                        BitmapFactory.Options options = new BitmapFactory.Options();
-                        return BitmapFactory.decodeStream(is, null, options);
-                    } catch (OutOfMemoryError e) {
-                        Log.w(TAG, "Can't decode stream", e);
-                    } finally {
-                        try {
-                            is.close();
-                        } catch (IOException e) {
-                            // Ignore
-                        }
+                        is.close();
+                    } catch (IOException e) {
+                        // Ignore
                     }
                 }
-            } catch (RemoteException e) {
-                // Ignore
             }
             return null;
         }
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 75b007c..646be06 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -570,7 +570,7 @@
     }
 
     /**
-     * Stop BLE advertising.
+     * Stop BLE advertising. The callback has to be the same one used for start advertising.
      *
      * @param callback - {@link AdvertiseCallback}
      * @return true if BLE advertising stops, false otherwise.
@@ -1989,7 +1989,13 @@
         public void onAdvertiseStateChange(int advertiseState, int status) {
             Log.d(TAG, "on advertise call back, state: " + advertiseState + " status: " + status);
             if (advertiseState == STATE_ADVERTISE_STARTED) {
-                mAdvertiseCallback.onAdvertiseStart(status);
+                if (status == ADVERTISE_CALLBACK_SUCCESS) {
+                    mAdvertiseCallback.onAdvertiseStart(status);
+                } else {
+                    // If status is unsuccessful and advertise state is started, it means stop
+                    // advertising fails.
+                    mAdvertiseCallback.onAdvertiseStop(status);
+                }
             } else {
                 synchronized (this) {
                     if (status == ADVERTISE_CALLBACK_SUCCESS) {
@@ -2011,8 +2017,22 @@
                         }
                     }
                 }
-                mAdvertiseCallback.onAdvertiseStop(status);
+                if (status == ADVERTISE_CALLBACK_SUCCESS) {
+                    mAdvertiseCallback.onAdvertiseStop(status);
+                } else{
+                    // If status is unsuccesful and advertise state is stopped, it means start
+                    // advertising fails.
+                    mAdvertiseCallback.onAdvertiseStart(status);
+                }
             }
         }
+
+        /**
+         * Callback reporting LE ATT MTU.
+         * @hide
+         */
+        public void onConfigureMTU(String address, int mtu, int status) {
+            // no op
+        }
     }
 }
diff --git a/core/java/android/bluetooth/BluetoothGatt.java b/core/java/android/bluetooth/BluetoothGatt.java
index ae6ad3b..e7ab8de 100644
--- a/core/java/android/bluetooth/BluetoothGatt.java
+++ b/core/java/android/bluetooth/BluetoothGatt.java
@@ -61,6 +61,7 @@
     private boolean mAutoConnect;
     private int mConnState;
     private final Object mStateLock = new Object();
+    private Boolean mDeviceBusy = false;
 
     private static final int CONN_STATE_IDLE = 0;
     private static final int CONN_STATE_CONNECTING = 1;
@@ -177,6 +178,10 @@
                         mConnState = CONN_STATE_IDLE;
                     }
                 }
+
+                synchronized(mDeviceBusy) {
+                    mDeviceBusy = false;
+                }
             }
 
             /**
@@ -312,6 +317,11 @@
                 if (!address.equals(mDevice.getAddress())) {
                     return;
                 }
+
+                synchronized(mDeviceBusy) {
+                    mDeviceBusy = false;
+                }
+
                 if ((status == GATT_INSUFFICIENT_AUTHENTICATION
                   || status == GATT_INSUFFICIENT_ENCRYPTION)
                   && mAuthRetry == false) {
@@ -359,6 +369,11 @@
                 if (!address.equals(mDevice.getAddress())) {
                     return;
                 }
+
+                synchronized(mDeviceBusy) {
+                    mDeviceBusy = false;
+                }
+
                 BluetoothGattService service = getService(mDevice, srvcUuid.getUuid(),
                                                           srvcInstId, srvcType);
                 if (service == null) return;
@@ -436,6 +451,11 @@
                 if (!address.equals(mDevice.getAddress())) {
                     return;
                 }
+
+                synchronized(mDeviceBusy) {
+                    mDeviceBusy = false;
+                }
+
                 BluetoothGattService service = getService(mDevice, srvcUuid.getUuid(),
                                                           srvcInstId, srvcType);
                 if (service == null) return;
@@ -485,6 +505,11 @@
                 if (!address.equals(mDevice.getAddress())) {
                     return;
                 }
+
+                synchronized(mDeviceBusy) {
+                    mDeviceBusy = false;
+                }
+
                 BluetoothGattService service = getService(mDevice, srvcUuid.getUuid(),
                                                           srvcInstId, srvcType);
                 if (service == null) return;
@@ -530,6 +555,11 @@
                 if (!address.equals(mDevice.getAddress())) {
                     return;
                 }
+
+                synchronized(mDeviceBusy) {
+                    mDeviceBusy = false;
+                }
+
                 try {
                     mCallback.onReliableWriteCompleted(BluetoothGatt.this, status);
                 } catch (Exception ex) {
@@ -561,6 +591,23 @@
             public void onAdvertiseStateChange(int state, int status) {
                 if (DBG) Log.d(TAG, "onAdvertiseStateChange() - state = "
                         + state + " status=" + status);
+	    }
+
+            /**
+             * Callback invoked when the MTU for a given connection changes
+             * @hide
+             */
+            public void onConfigureMTU(String address, int mtu, int status) {
+                if (DBG) Log.d(TAG, "onConfigureMTU() - Device=" + address +
+                            " mtu=" + mtu + " status=" + status);
+                if (!address.equals(mDevice.getAddress())) {
+                    return;
+                }
+                try {
+                    mCallback.onConfigureMTU(BluetoothGatt.this, mtu, status);
+                } catch (Exception ex) {
+                    Log.w(TAG, "Unhandled exception in callback", ex);
+                }
             }
         };
 
@@ -845,6 +892,11 @@
         BluetoothDevice device = service.getDevice();
         if (device == null) return false;
 
+        synchronized(mDeviceBusy) {
+            if (mDeviceBusy) return false;
+            mDeviceBusy = true;
+        }
+
         try {
             mService.readCharacteristic(mClientIf, device.getAddress(),
                 service.getType(), service.getInstanceId(),
@@ -852,6 +904,7 @@
                 new ParcelUuid(characteristic.getUuid()), AUTHENTICATION_NONE);
         } catch (RemoteException e) {
             Log.e(TAG,"",e);
+            mDeviceBusy = false;
             return false;
         }
 
@@ -884,6 +937,11 @@
         BluetoothDevice device = service.getDevice();
         if (device == null) return false;
 
+        synchronized(mDeviceBusy) {
+            if (mDeviceBusy) return false;
+            mDeviceBusy = true;
+        }
+
         try {
             mService.writeCharacteristic(mClientIf, device.getAddress(),
                 service.getType(), service.getInstanceId(),
@@ -893,6 +951,7 @@
                 characteristic.getValue());
         } catch (RemoteException e) {
             Log.e(TAG,"",e);
+            mDeviceBusy = false;
             return false;
         }
 
@@ -924,6 +983,11 @@
         BluetoothDevice device = service.getDevice();
         if (device == null) return false;
 
+        synchronized(mDeviceBusy) {
+            if (mDeviceBusy) return false;
+            mDeviceBusy = true;
+        }
+
         try {
             mService.readDescriptor(mClientIf, device.getAddress(), service.getType(),
                 service.getInstanceId(), new ParcelUuid(service.getUuid()),
@@ -932,6 +996,7 @@
                 AUTHENTICATION_NONE);
         } catch (RemoteException e) {
             Log.e(TAG,"",e);
+            mDeviceBusy = false;
             return false;
         }
 
@@ -962,6 +1027,11 @@
         BluetoothDevice device = service.getDevice();
         if (device == null) return false;
 
+        synchronized(mDeviceBusy) {
+            if (mDeviceBusy) return false;
+            mDeviceBusy = true;
+        }
+
         try {
             mService.writeDescriptor(mClientIf, device.getAddress(), service.getType(),
                 service.getInstanceId(), new ParcelUuid(service.getUuid()),
@@ -971,6 +1041,7 @@
                 descriptor.getValue());
         } catch (RemoteException e) {
             Log.e(TAG,"",e);
+            mDeviceBusy = false;
             return false;
         }
 
@@ -1028,10 +1099,16 @@
         if (DBG) Log.d(TAG, "executeReliableWrite() - device: " + mDevice.getAddress());
         if (mService == null || mClientIf == 0) return false;
 
+        synchronized(mDeviceBusy) {
+            if (mDeviceBusy) return false;
+            mDeviceBusy = true;
+        }
+
         try {
             mService.endReliableWrite(mClientIf, mDevice.getAddress(), true);
         } catch (RemoteException e) {
             Log.e(TAG,"",e);
+            mDeviceBusy = false;
             return false;
         }
 
@@ -1148,6 +1225,36 @@
     }
 
     /**
+     * Configure the MTU used for a given connection.
+     *
+     * <p>When performing a write request operation (write without response),
+     * the data sent is truncated to the MTU size. This function may be used
+     * to request a larget MTU size to be able to send more data at once.
+     *
+     * <p>A {@link BluetoothGattCallback#onConfigureMTU} callback will indicate
+     * whether this operation was successful.
+     *
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+     *
+     * @return true, if the new MTU value has been requested successfully
+     * @hide
+     */
+    public boolean configureMTU(int mtu) {
+        if (DBG) Log.d(TAG, "configureMTU() - device: " + mDevice.getAddress()
+                            + " mtu: " + mtu);
+        if (mService == null || mClientIf == 0) return false;
+
+        try {
+            mService.configureMTU(mClientIf, mDevice.getAddress(), mtu);
+        } catch (RemoteException e) {
+            Log.e(TAG,"",e);
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
      * Not supported - please use {@link BluetoothManager#getConnectedDevices(int)}
      * with {@link BluetoothProfile#GATT} as argument
      *
diff --git a/core/java/android/bluetooth/BluetoothGattCallback.java b/core/java/android/bluetooth/BluetoothGattCallback.java
index 80ea4a6..5180259 100644
--- a/core/java/android/bluetooth/BluetoothGattCallback.java
+++ b/core/java/android/bluetooth/BluetoothGattCallback.java
@@ -138,4 +138,19 @@
      */
     public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
     }
+
+    /**
+     * Callback indicating the MTU for a given device connection has changed.
+     *
+     * This callback is triggered in response to the
+     * {@link BluetoothGatt#configureMTU} function, or in response to a connection
+     * event.
+     *
+     * @param gatt GATT client invoked {@link BluetoothGatt#configureMTU}
+     * @param mtu The new MTU size
+     * @param status {@link BluetoothGatt#GATT_SUCCESS} if the MTU has been changed successfully
+     * @hide
+     */
+    public void onConfigureMTU(BluetoothGatt gatt, int mtu, int status) {
+    }
 }
diff --git a/core/java/android/bluetooth/BluetoothInputDevice.java b/core/java/android/bluetooth/BluetoothInputDevice.java
index 844f432..c48b15d 100644
--- a/core/java/android/bluetooth/BluetoothInputDevice.java
+++ b/core/java/android/bluetooth/BluetoothInputDevice.java
@@ -76,6 +76,19 @@
     public static final String ACTION_PROTOCOL_MODE_CHANGED =
         "android.bluetooth.input.profile.action.PROTOCOL_MODE_CHANGED";
 
+    /**
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_HANDSHAKE =
+        "android.bluetooth.input.profile.action.HANDSHAKE";
+
+    /**
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_REPORT =
+        "android.bluetooth.input.profile.action.REPORT";
 
     /**
      * @hide
@@ -130,17 +143,17 @@
     /**
      * @hide
      */
-    public static final byte REPORT_TYPE_INPUT = 0;
+    public static final byte REPORT_TYPE_INPUT = 1;
 
     /**
      * @hide
      */
-    public static final byte REPORT_TYPE_OUTPUT = 1;
+    public static final byte REPORT_TYPE_OUTPUT = 2;
 
     /**
      * @hide
      */
-    public static final byte REPORT_TYPE_FEATURE = 2;
+    public static final byte REPORT_TYPE_FEATURE = 3;
 
     /**
      * @hide
@@ -180,6 +193,11 @@
     /**
      * @hide
      */
+    public static final String EXTRA_STATUS = "android.bluetooth.BluetoothInputDevice.extra.STATUS";
+
+    /**
+     * @hide
+     */
     public static final String EXTRA_VIRTUAL_UNPLUG_STATUS = "android.bluetooth.BluetoothInputDevice.extra.VIRTUAL_UNPLUG_STATUS";
 
     private Context mContext;
@@ -603,7 +621,7 @@
      * @hide
      */
     public boolean setReport(BluetoothDevice device, byte reportType, String report) {
-        if (DBG) log("setReport(" + device + "), reportType=" + reportType + " report=" + report);
+        if (VDBG) log("setReport(" + device + "), reportType=" + reportType + " report=" + report);
         if (mService != null && isEnabled() && isValidDevice(device)) {
             try {
                 return mService.setReport(device, reportType, report);
diff --git a/core/java/android/bluetooth/BluetoothSocket.java b/core/java/android/bluetooth/BluetoothSocket.java
index d10eaea..1e75fc2 100644
--- a/core/java/android/bluetooth/BluetoothSocket.java
+++ b/core/java/android/bluetooth/BluetoothSocket.java
@@ -417,27 +417,28 @@
      *             if an i/o error occurs.
      */
     /*package*/ void flush() throws IOException {
+        if (mSocketOS == null) throw new IOException("flush is called on null OutputStream");
         if (VDBG) Log.d(TAG, "flush: " + mSocketOS);
         mSocketOS.flush();
     }
 
     /*package*/ int read(byte[] b, int offset, int length) throws IOException {
-
-            if (VDBG) Log.d(TAG, "read in:  " + mSocketIS + " len: " + length);
-            int ret = mSocketIS.read(b, offset, length);
-            if(ret < 0)
-                throw new IOException("bt socket closed, read return: " + ret);
-            if (VDBG) Log.d(TAG, "read out:  " + mSocketIS + " ret: " + ret);
-            return ret;
+        if (mSocketIS == null) throw new IOException("read is called on null InputStream");
+        if (VDBG) Log.d(TAG, "read in:  " + mSocketIS + " len: " + length);
+        int ret = mSocketIS.read(b, offset, length);
+        if(ret < 0)
+            throw new IOException("bt socket closed, read return: " + ret);
+        if (VDBG) Log.d(TAG, "read out:  " + mSocketIS + " ret: " + ret);
+        return ret;
     }
 
     /*package*/ int write(byte[] b, int offset, int length) throws IOException {
-
-            if (VDBG) Log.d(TAG, "write: " + mSocketOS + " length: " + length);
-            mSocketOS.write(b, offset, length);
-            // There is no good way to confirm since the entire process is asynchronous anyway
-            if (VDBG) Log.d(TAG, "write out: " + mSocketOS + " length: " + length);
-            return length;
+        if (mSocketOS == null) throw new IOException("write is called on null OutputStream");
+        if (VDBG) Log.d(TAG, "write: " + mSocketOS + " length: " + length);
+        mSocketOS.write(b, offset, length);
+        // There is no good way to confirm since the entire process is asynchronous anyway
+        if (VDBG) Log.d(TAG, "write out: " + mSocketOS + " length: " + length);
+        return length;
     }
 
     @Override
diff --git a/core/java/android/bluetooth/BluetoothTetheringDataTracker.java b/core/java/android/bluetooth/BluetoothTetheringDataTracker.java
index a9b7176..7745bb7 100644
--- a/core/java/android/bluetooth/BluetoothTetheringDataTracker.java
+++ b/core/java/android/bluetooth/BluetoothTetheringDataTracker.java
@@ -61,6 +61,9 @@
     private static final boolean DBG = true;
     private static final boolean VDBG = true;
 
+    // Event sent to the mBtdtHandler when DHCP fails so we can tear down the network.
+    private static final int EVENT_NETWORK_FAILED = 1;
+
     private AtomicBoolean mTeardownRequested = new AtomicBoolean(false);
     private AtomicBoolean mPrivateDnsRouteSet = new AtomicBoolean(false);
     private AtomicInteger mDefaultGatewayAddr = new AtomicInteger(0);
@@ -328,6 +331,7 @@
                     }
                     if (!success) {
                         Log.e(TAG, "DHCP request error:" + NetworkUtils.getDhcpError());
+                        mBtdtHandler.obtainMessage(EVENT_NETWORK_FAILED).sendToTarget();
                         return;
                     }
                     mLinkProperties = dhcpResults.linkProperties;
@@ -420,6 +424,10 @@
                     if (VDBG) Log.d(TAG, "got EVENT_NETWORK_DISCONNECTED, " + linkProperties);
                     mBtdt.stopReverseTether();
                     break;
+                case EVENT_NETWORK_FAILED:
+                    if (VDBG) Log.d(TAG, "got EVENT_NETWORK_FAILED");
+                    mBtdt.teardown();
+                    break;
             }
         }
     }
diff --git a/core/java/android/bluetooth/IBluetoothGatt.aidl b/core/java/android/bluetooth/IBluetoothGatt.aidl
index 784cdcc..c6b5c3d 100644
--- a/core/java/android/bluetooth/IBluetoothGatt.aidl
+++ b/core/java/android/bluetooth/IBluetoothGatt.aidl
@@ -73,6 +73,7 @@
     void beginReliableWrite(in int clientIf, in String address);
     void endReliableWrite(in int clientIf, in String address, in boolean execute);
     void readRemoteRssi(in int clientIf, in String address);
+    void configureMTU(in int clientIf, in String address, in int mtu);
 
     void registerServer(in ParcelUuid appId, in IBluetoothGattServerCallback callback);
     void unregisterServer(in int serverIf);
diff --git a/core/java/android/bluetooth/IBluetoothGattCallback.aidl b/core/java/android/bluetooth/IBluetoothGattCallback.aidl
index 7c69a06..a78c29b 100644
--- a/core/java/android/bluetooth/IBluetoothGattCallback.aidl
+++ b/core/java/android/bluetooth/IBluetoothGattCallback.aidl
@@ -64,4 +64,5 @@
                              in byte[] value);
     void onReadRemoteRssi(in String address, in int rssi, in int status);
     oneway void onAdvertiseStateChange(in int advertiseState, in int status);
+    void onConfigureMTU(in String address, in int mtu, in int status);
 }
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 2e4e209..bfdb46a 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -530,6 +530,9 @@
      * Open a private file associated with this Context's application package
      * for writing.  Creates the file if it doesn't already exist.
      *
+     * <p>No permissions are required to invoke this method, since it uses internal
+     * storage.
+     *
      * @param name The name of the file to open; can not contain path
      *             separators.
      * @param mode Operating mode.  Use 0 or {@link #MODE_PRIVATE} for the
@@ -587,6 +590,9 @@
      * Returns the absolute path to the directory on the filesystem where
      * files created with {@link #openFileOutput} are stored.
      *
+     * <p>No permissions are required to read or write to the returned path, since this
+     * path is internal storage.
+     *
      * @return The path of the directory holding application files.
      *
      * @see #openFileOutput
@@ -1798,7 +1804,7 @@
      * @hide like {@link #stopService(Intent)} but for a specific user.
      */
     public abstract boolean stopServiceAsUser(Intent service, UserHandle user);
-    
+
     /**
      * Connect to an application service, creating it if needed.  This defines
      * a dependency between your application and the service.  The given
@@ -1974,6 +1980,8 @@
      * @see android.app.SearchManager
      * @see #SENSOR_SERVICE
      * @see android.hardware.SensorManager
+     * @see #HDMI_CEC_SERVICE
+     * @see android.hardware.hdmi.HdmiCecManager
      * @see #STORAGE_SERVICE
      * @see android.os.storage.StorageManager
      * @see #VIBRATOR_SERVICE
@@ -2389,6 +2397,17 @@
 
     /**
      * Use with {@link #getSystemService} to retrieve a
+     * {@link android.hardware.hdmi.HdmiCecManager for controlling and managing
+     * HDMI-CEC protocol.
+     *
+     * @see #getSystemService
+     * @see android.hardware.hdmi.HdmiCecManager
+     * @hide
+     */
+     public static final String HDMI_CEC_SERVICE = "hdmi_cec";
+
+    /**
+     * Use with {@link #getSystemService} to retrieve a
      * {@link android.hardware.input.InputManager} for interacting with input devices.
      *
      * @see #getSystemService
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index a50b650..b1a743b 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1414,15 +1414,38 @@
     // Standard intent broadcast actions (see action variable).
 
     /**
-     * Broadcast Action: Sent after the screen turns off.
+     * Broadcast Action: Sent when the device goes to sleep and becomes non-interactive.
+     * <p>
+     * For historical reasons, the name of this broadcast action refers to the power
+     * state of the screen but it is actually sent in response to changes in the
+     * overall interactive state of the device.
+     * </p><p>
+     * This broadcast is sent when the device becomes non-interactive which may have
+     * nothing to do with the screen turning off.  To determine the
+     * actual state of the screen, use {@link android.view.Display#getState}.
+     * </p><p>
+     * See {@link android.os.PowerManager#isInteractive} for details.
+     * </p>
      *
      * <p class="note">This is a protected intent that can only be sent
      * by the system.
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_SCREEN_OFF = "android.intent.action.SCREEN_OFF";
+
     /**
-     * Broadcast Action: Sent after the screen turns on.
+     * Broadcast Action: Sent when the device wakes up and becomes interactive.
+     * <p>
+     * For historical reasons, the name of this broadcast action refers to the power
+     * state of the screen but it is actually sent in response to changes in the
+     * overall interactive state of the device.
+     * </p><p>
+     * This broadcast is sent when the device becomes interactive which may have
+     * nothing to do with the screen turning on.  To determine the
+     * actual state of the screen, use {@link android.view.Display#getState}.
+     * </p><p>
+     * See {@link android.os.PowerManager#isInteractive} for details.
+     * </p>
      *
      * <p class="note">This is a protected intent that can only be sent
      * by the system.
@@ -2765,6 +2788,13 @@
     @SdkConstant(SdkConstantType.INTENT_CATEGORY)
     public static final String CATEGORY_LAUNCHER = "android.intent.category.LAUNCHER";
     /**
+     * Indicates an activity optimized for Leanback mode, and that should
+     * be displayed in the Leanback launcher.
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.INTENT_CATEGORY)
+    public static final String CATEGORY_LEANBACK_LAUNCHER = "android.intent.category.LEANBACK_LAUNCHER";
+    /**
      * Provides information about the package it is in; typically used if
      * a package does not contain a {@link #CATEGORY_LAUNCHER} to provide
      * a front-door to the user without having to be shown in the all apps list.
@@ -3547,6 +3577,11 @@
      * it will be finished so that the user does not return to them, but
      * instead returns to whatever activity preceeded it.
      *
+     * <p>When this flag is assigned to the root activity all activities up
+     * to, but not including the root activity, will be cleared. This prevents
+     * this flag from being used to finish all activities in a task and thereby
+     * ending the task.
+     *
      * <p>This is useful for cases where you have a logical break in your
      * application.  For example, an e-mail application may have a command
      * to view an attachment, which launches an image view activity to
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index b8ac3bf..941b726 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -187,7 +187,7 @@
     /**
      * @hide Bit in {@link #flags}: If set, this component will only be seen
      * by the primary user.  Only works with broadcast receivers.  Set from the
-     * {@link android.R.attr#primaryUserOnly} attribute.
+     * android.R.attr#primaryUserOnly attribute.
      */
     public static final int FLAG_PRIMARY_USER_ONLY = 0x20000000;
     /**
@@ -199,6 +199,13 @@
      */
     public static final int FLAG_SINGLE_USER = 0x40000000;
     /**
+     * @hide Bit in {@link #flags}: If set, this activity may be launched into an
+     * owned ActivityContainer such as that within an ActivityView. If not set and
+     * this activity is launched into such a container a SecurityExcception will be
+     * thrown. Set from the {@link android.R.attr#allowEmbedded} attribute.
+     */
+    public static final int FLAG_ALLOW_EMBEDDED = 0x80000000;
+    /**
      * Options that have been set in the activity declaration in the
      * manifest.
      * These include:
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index a23cd7f..2639625 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -315,6 +315,14 @@
     public static final int FLAG_IS_DATA_ONLY = 1<<24;
 
     /**
+     * Value for {@link #flags}: true if the application was declared to be a game, or
+     * false if it is a non-game application.
+     *
+     * {@hide}
+     */
+    public static final int FLAG_IS_GAME = 1<<25;
+
+    /**
      * Value for {@link #flags}: set to {@code true} if the application
      * is permitted to hold privileged permissions.
      *
@@ -483,7 +491,7 @@
      * @hide
      */
     public int installLocation = PackageInfo.INSTALL_LOCATION_UNSPECIFIED;
-    
+
     public void dump(Printer pw, String prefix) {
         super.dumpFront(pw, prefix);
         if (className != null) {
diff --git a/core/java/android/content/pm/ComponentInfo.java b/core/java/android/content/pm/ComponentInfo.java
index 4dbcf23..7e8f285 100644
--- a/core/java/android/content/pm/ComponentInfo.java
+++ b/core/java/android/content/pm/ComponentInfo.java
@@ -128,6 +128,17 @@
         return logo != 0 ? logo : applicationInfo.logo;
     }
     
+    /**
+     * Return the banner resource identifier to use for this component. If the
+     * component defines a banner, that is used; else, the application banner is
+     * used.
+     *
+     * @return The banner associated with this component.
+     */
+    public final int getBannerResource() {
+        return banner != 0 ? banner : applicationInfo.banner;
+    }
+
     protected void dumpFront(Printer pw, String prefix) {
         super.dumpFront(pw, prefix);
         pw.println(prefix + "enabled=" + enabled + " exported=" + exported
@@ -175,6 +186,13 @@
     /**
      * @hide
      */
+    @Override protected Drawable loadDefaultBanner(PackageManager pm) {
+        return applicationInfo.loadBanner(pm);
+    }
+
+    /**
+     * @hide
+     */
     @Override
     protected Drawable loadDefaultLogo(PackageManager pm) {
         return applicationInfo.loadLogo(pm);
diff --git a/core/java/android/content/pm/PackageItemInfo.java b/core/java/android/content/pm/PackageItemInfo.java
index a67326e..58f1c84 100644
--- a/core/java/android/content/pm/PackageItemInfo.java
+++ b/core/java/android/content/pm/PackageItemInfo.java
@@ -68,6 +68,12 @@
     
     /**
      * A drawable resource identifier (in the package's resources) of this
+     * component's banner.  From the "banner" attribute or, if not set, 0.
+     */
+    public int banner;
+
+    /**
+     * A drawable resource identifier (in the package's resources) of this
      * component's logo. Logos may be larger/wider than icons and are
      * displayed by certain UI elements in place of a name or name/icon
      * combination. From the "logo" attribute or, if not set, 0. 
@@ -92,6 +98,7 @@
         nonLocalizedLabel = orig.nonLocalizedLabel;
         if (nonLocalizedLabel != null) nonLocalizedLabel = nonLocalizedLabel.toString().trim();
         icon = orig.icon;
+        banner = orig.banner;
         logo = orig.logo;
         metaData = orig.metaData;
     }
@@ -146,6 +153,27 @@
     }
     
     /**
+     * Retrieve the current graphical banner associated with this item.  This
+     * will call back on the given PackageManager to load the banner from
+     * the application.
+     *
+     * @param pm A PackageManager from which the banner can be loaded; usually
+     * the PackageManager from which you originally retrieved this item.
+     *
+     * @return Returns a Drawable containing the item's banner.  If the item
+     * does not have a banner, this method will return null.
+     */
+    public Drawable loadBanner(PackageManager pm) {
+        if (banner != 0) {
+            Drawable dr = pm.getDrawable(packageName, banner, getApplicationInfo());
+            if (dr != null) {
+                return dr;
+            }
+        }
+        return loadDefaultBanner(pm);
+    }
+
+    /**
      * Retrieve the default graphical icon associated with this item.
      * 
      * @param pm A PackageManager from which the icon can be loaded; usually
@@ -159,7 +187,22 @@
     protected Drawable loadDefaultIcon(PackageManager pm) {
         return pm.getDefaultActivityIcon();
     }
-    
+
+    /**
+     * Retrieve the default graphical banner associated with this item.
+     *
+     * @param pm A PackageManager from which the banner can be loaded; usually
+     * the PackageManager from which you originally retrieved this item.
+     *
+     * @return Returns a Drawable containing the item's default banner
+     * or null if no default logo is available.
+     *
+     * @hide
+     */
+    protected Drawable loadDefaultBanner(PackageManager pm) {
+        return null;
+    }
+
     /**
      * Retrieve the current graphical logo associated with this item. This
      * will call back on the given PackageManager to load the logo from
@@ -224,10 +267,11 @@
             pw.println(prefix + "name=" + name);
         }
         pw.println(prefix + "packageName=" + packageName);
-        if (labelRes != 0 || nonLocalizedLabel != null || icon != 0) {
+        if (labelRes != 0 || nonLocalizedLabel != null || icon != 0 || banner != 0) {
             pw.println(prefix + "labelRes=0x" + Integer.toHexString(labelRes)
                     + " nonLocalizedLabel=" + nonLocalizedLabel
-                    + " icon=0x" + Integer.toHexString(icon));
+                    + " icon=0x" + Integer.toHexString(icon)
+                    + " banner=0x" + Integer.toHexString(banner));
         }
     }
     
@@ -243,6 +287,7 @@
         dest.writeInt(icon);
         dest.writeInt(logo);
         dest.writeBundle(metaData);
+        dest.writeInt(banner);
     }
     
     protected PackageItemInfo(Parcel source) {
@@ -254,6 +299,7 @@
         icon = source.readInt();
         logo = source.readInt();
         metaData = source.readBundle();
+        banner = source.readInt();
     }
 
     /**
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 8ce7e97..6413bb4 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -913,13 +913,21 @@
     /**
      * Feature for {@link #getSystemAvailableFeatures} and
      * {@link #hasSystemFeature}: The device has at least one camera pointing in
-     * some direction.
+     * some direction, or can support an external camera being connected to it.
      */
     @SdkConstant(SdkConstantType.FEATURE)
     public static final String FEATURE_CAMERA_ANY = "android.hardware.camera.any";
 
     /**
      * Feature for {@link #getSystemAvailableFeatures} and
+     * {@link #hasSystemFeature}: The device can support having an external camera connected to it.
+     * The external camera may not always be connected or available to applications to use.
+     */
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_CAMERA_EXTERNAL = "android.hardware.camera.external";
+
+    /**
+     * Feature for {@link #getSystemAvailableFeatures} and
      * {@link #hasSystemFeature}: The device's camera supports flash.
      */
     @SdkConstant(SdkConstantType.FEATURE)
@@ -989,6 +997,7 @@
      * @hide
      * @deprecated
      */
+    @Deprecated
     @SdkConstant(SdkConstantType.FEATURE)
     public static final String FEATURE_NFC_HCE = "android.hardware.nfc.hce";
 
@@ -1059,6 +1068,13 @@
 
     /**
      * Feature for {@link #getSystemAvailableFeatures} and
+     * {@link #hasSystemFeature}: The device includes a heart rate monitor.
+     */
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_SENSOR_HEART_RATE = "android.hardware.sensor.heartrate";
+
+    /**
+     * Feature for {@link #getSystemAvailableFeatures} and
      * {@link #hasSystemFeature}: The device has a telephony radio with data
      * communication support.
      */
@@ -1244,6 +1260,27 @@
 
     /**
      * Feature for {@link #getSystemAvailableFeatures} and
+     * {@link #hasSystemFeature}: The device supports leanback UI. This is
+     * typically used in a living room television experience, but is a software
+     * feature unlike {@link #FEATURE_TELEVISION}. Devices running with this
+     * feature will use resources associated with the "television" UI mode.
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_LEANBACK = "android.software.leanback";
+
+    /**
+     * Feature for {@link #getSystemAvailableFeatures} and
+     * {@link #hasSystemFeature}: The device supports only leanback UI. Only
+     * applications designed for this experience should be run, though this is
+     * not enforced by the system.
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_LEANBACK_ONLY = "android.software.leanback_only";
+
+    /**
+     * Feature for {@link #getSystemAvailableFeatures} and
      * {@link #hasSystemFeature}: The device supports WiFi (802.11) networking.
      */
     @SdkConstant(SdkConstantType.FEATURE)
@@ -1268,6 +1305,29 @@
     public static final String FEATURE_TELEVISION = "android.hardware.type.television";
 
     /**
+     * Feature for {@link #getSystemAvailableFeatures} and
+     * {@link #hasSystemFeature}: This is a device dedicated to showing UI
+     * on a watch. A watch here is defined to be a device worn on the body, perhaps on
+     * the wrist. The user is very close when interacting with the device.
+     */
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_WATCH = "android.hardware.type.watch";
+
+    /**
+     * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}:
+     * The device supports printing.
+     */
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_PRINTING = "android.software.print";
+
+    /**
+     * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}:
+     * The device can perform backup and restore operations on installed applications.
+     */
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_BACKUP = "android.software.backup";
+
+    /**
      * Action to external storage service to clean out removed apps.
      * @hide
      */
@@ -1430,17 +1490,33 @@
     public abstract Intent getLaunchIntentForPackage(String packageName);
 
     /**
-     * Return an array of all of the secondary group-ids that have been
-     * assigned to a package.
-     *
-     * <p>Throws {@link NameNotFoundException} if a package with the given
-     * name cannot be found on the system.
-     *
+     * @hide Return a "good" intent to launch a front-door Leanback activity in a
+     * package, for use for example to implement an "open" button when browsing
+     * through packages. The current implementation will look for a main
+     * activity in the category {@link Intent#CATEGORY_LEANBACK_LAUNCHER}, or
+     * return null if no main leanback activities are found.
+     * <p>
+     * Throws {@link NameNotFoundException} if a package with the given name
+     * cannot be found on the system.
+     * 
+     * @param packageName The name of the package to inspect.
+     * @return Returns either a fully-qualified Intent that can be used to launch
+     *         the main Leanback activity in the package, or null if the package
+     *         does not contain such an activity.
+     */
+    public abstract Intent getLeanbackLaunchIntentForPackage(String packageName);
+
+    /**
+     * Return an array of all of the secondary group-ids that have been assigned
+     * to a package.
+     * <p>
+     * Throws {@link NameNotFoundException} if a package with the given name
+     * cannot be found on the system.
+     * 
      * @param packageName The full name (i.e. com.google.apps.contacts) of the
-     *                    desired package.
-     *
-     * @return Returns an int array of the assigned gids, or null if there
-     * are none.
+     *            desired package.
+     * @return Returns an int array of the assigned gids, or null if there are
+     *         none.
      */
     public abstract int[] getPackageGids(String packageName)
             throws NameNotFoundException;
@@ -2388,6 +2464,40 @@
             throws NameNotFoundException;
 
     /**
+     * Retrieve the banner associated with an activity. Given the full name of
+     * an activity, retrieves the information about it and calls
+     * {@link ComponentInfo#loadIcon ComponentInfo.loadIcon()} to return its
+     * banner. If the activity cannot be found, NameNotFoundException is thrown.
+     *
+     * @param activityName Name of the activity whose banner is to be retrieved.
+     * @return Returns the image of the banner, or null if the activity has no
+     *         banner specified.
+     * @throws NameNotFoundException Thrown if the resources for the given
+     *             activity could not be loaded.
+     * @see #getActivityBanner(Intent)
+     */
+    public abstract Drawable getActivityBanner(ComponentName activityName)
+            throws NameNotFoundException;
+
+    /**
+     * Retrieve the banner associated with an Intent. If intent.getClassName()
+     * is set, this simply returns the result of
+     * getActivityBanner(intent.getClassName()). Otherwise it resolves the
+     * intent's component and returns the banner associated with the resolved
+     * component. If intent.getClassName() cannot be found or the Intent cannot
+     * be resolved to a component, NameNotFoundException is thrown.
+     *
+     * @param intent The intent for which you would like to retrieve a banner.
+     * @return Returns the image of the banner, or null if the activity has no
+     *         banner specified.
+     * @throws NameNotFoundException Thrown if the resources for application
+     *             matching the given intent could not be loaded.
+     * @see #getActivityBanner(ComponentName)
+     */
+    public abstract Drawable getActivityBanner(Intent intent)
+            throws NameNotFoundException;
+
+    /**
      * Return the generic icon for an activity that is used when no specific
      * icon is defined.
      *
@@ -2428,19 +2538,43 @@
             throws NameNotFoundException;
 
     /**
-     * Retrieve the logo associated with an activity.  Given the full name of
-     * an activity, retrieves the information about it and calls
-     * {@link ComponentInfo#loadLogo ComponentInfo.loadLogo()} to return its logo.
-     * If the activity cannot be found, NameNotFoundException is thrown.
+     * Retrieve the banner associated with an application.
+     *
+     * @param info Information about application being queried.
+     * @return Returns the image of the banner or null if the application has no
+     *         banner specified.
+     * @see #getApplicationBanner(String)
+     */
+    public abstract Drawable getApplicationBanner(ApplicationInfo info);
+
+    /**
+     * Retrieve the banner associated with an application. Given the name of the
+     * application's package, retrieves the information about it and calls
+     * getApplicationIcon() to return its banner. If the application cannot be
+     * found, NameNotFoundException is thrown.
+     *
+     * @param packageName Name of the package whose application banner is to be
+     *            retrieved.
+     * @return Returns the image of the banner or null if the application has no
+     *         banner specified.
+     * @throws NameNotFoundException Thrown if the resources for the given
+     *             application could not be loaded.
+     * @see #getApplicationBanner(ApplicationInfo)
+     */
+    public abstract Drawable getApplicationBanner(String packageName)
+            throws NameNotFoundException;
+
+    /**
+     * Retrieve the logo associated with an activity. Given the full name of an
+     * activity, retrieves the information about it and calls
+     * {@link ComponentInfo#loadLogo ComponentInfo.loadLogo()} to return its
+     * logo. If the activity cannot be found, NameNotFoundException is thrown.
      *
      * @param activityName Name of the activity whose logo is to be retrieved.
-     *
-     * @return Returns the image of the logo or null if the activity has no
-     * logo specified.
-     *
+     * @return Returns the image of the logo or null if the activity has no logo
+     *         specified.
      * @throws NameNotFoundException Thrown if the resources for the given
-     * activity could not be loaded.
-     *
+     *             activity could not be loaded.
      * @see #getActivityLogo(Intent)
      */
     public abstract Drawable getActivityLogo(ComponentName activityName)
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index c0963f5..66b2bb2 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -167,18 +167,20 @@
         final int labelRes;
         final int iconRes;
         final int logoRes;
+        final int bannerRes;
         
         String tag;
         TypedArray sa;
         
         ParsePackageItemArgs(Package _owner, String[] _outError,
-                int _nameRes, int _labelRes, int _iconRes, int _logoRes) {
+                int _nameRes, int _labelRes, int _iconRes, int _logoRes, int _bannerRes) {
             owner = _owner;
             outError = _outError;
             nameRes = _nameRes;
             labelRes = _labelRes;
             iconRes = _iconRes;
             logoRes = _logoRes;
+            bannerRes = _bannerRes;
         }
     }
     
@@ -190,10 +192,10 @@
         int flags;
         
         ParseComponentArgs(Package _owner, String[] _outError,
-                int _nameRes, int _labelRes, int _iconRes, int _logoRes,
+                int _nameRes, int _labelRes, int _iconRes, int _logoRes, int _bannerRes,
                 String[] _sepProcesses, int _processRes,
                 int _descriptionRes, int _enabledRes) {
-            super(_owner, _outError, _nameRes, _labelRes, _iconRes, _logoRes);
+            super(_owner, _outError, _nameRes, _labelRes, _iconRes, _logoRes, _bannerRes);
             sepProcesses = _sepProcesses;
             processRes = _processRes;
             descriptionRes = _descriptionRes;
@@ -1687,7 +1689,8 @@
                 com.android.internal.R.styleable.AndroidManifestPermissionGroup_name,
                 com.android.internal.R.styleable.AndroidManifestPermissionGroup_label,
                 com.android.internal.R.styleable.AndroidManifestPermissionGroup_icon,
-                com.android.internal.R.styleable.AndroidManifestPermissionGroup_logo)) {
+                com.android.internal.R.styleable.AndroidManifestPermissionGroup_logo,
+                com.android.internal.R.styleable.AndroidManifestPermissionGroup_banner)) {
             sa.recycle();
             mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
             return null;
@@ -1730,7 +1733,8 @@
                 com.android.internal.R.styleable.AndroidManifestPermission_name,
                 com.android.internal.R.styleable.AndroidManifestPermission_label,
                 com.android.internal.R.styleable.AndroidManifestPermission_icon,
-                com.android.internal.R.styleable.AndroidManifestPermission_logo)) {
+                com.android.internal.R.styleable.AndroidManifestPermission_logo,
+                com.android.internal.R.styleable.AndroidManifestPermission_banner)) {
             sa.recycle();
             mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
             return null;
@@ -1799,7 +1803,8 @@
                 com.android.internal.R.styleable.AndroidManifestPermissionTree_name,
                 com.android.internal.R.styleable.AndroidManifestPermissionTree_label,
                 com.android.internal.R.styleable.AndroidManifestPermissionTree_icon,
-                com.android.internal.R.styleable.AndroidManifestPermissionTree_logo)) {
+                com.android.internal.R.styleable.AndroidManifestPermissionTree_logo,
+                com.android.internal.R.styleable.AndroidManifestPermissionTree_banner)) {
             sa.recycle();
             mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
             return null;
@@ -1844,7 +1849,8 @@
                     com.android.internal.R.styleable.AndroidManifestInstrumentation_name,
                     com.android.internal.R.styleable.AndroidManifestInstrumentation_label,
                     com.android.internal.R.styleable.AndroidManifestInstrumentation_icon,
-                    com.android.internal.R.styleable.AndroidManifestInstrumentation_logo);
+                    com.android.internal.R.styleable.AndroidManifestInstrumentation_logo,
+                    com.android.internal.R.styleable.AndroidManifestInstrumentation_banner);
             mParseInstrumentationArgs.tag = "<instrumentation>";
         }
         
@@ -1960,6 +1966,8 @@
                 com.android.internal.R.styleable.AndroidManifestApplication_icon, 0);
         ai.logo = sa.getResourceId(
                 com.android.internal.R.styleable.AndroidManifestApplication_logo, 0);
+        ai.banner = sa.getResourceId(
+                com.android.internal.R.styleable.AndroidManifestApplication_banner, 0);
         ai.theme = sa.getResourceId(
                 com.android.internal.R.styleable.AndroidManifestApplication_theme, 0);
         ai.descriptionRes = sa.getResourceId(
@@ -2081,6 +2089,11 @@
             ai.enabled = sa.getBoolean(
                     com.android.internal.R.styleable.AndroidManifestApplication_enabled, true);
             
+            if (sa.getBoolean(
+                    com.android.internal.R.styleable.AndroidManifestApplication_isGame, false)) {
+                ai.flags |= ApplicationInfo.FLAG_IS_GAME;
+            }
+
             if (false) {
                 if (sa.getBoolean(
                         com.android.internal.R.styleable.AndroidManifestApplication_cantSaveState,
@@ -2253,7 +2266,7 @@
 
     private boolean parsePackageItemInfo(Package owner, PackageItemInfo outInfo,
             String[] outError, String tag, TypedArray sa,
-            int nameRes, int labelRes, int iconRes, int logoRes) {
+            int nameRes, int labelRes, int iconRes, int logoRes, int bannerRes) {
         String name = sa.getNonConfigurationString(nameRes, 0);
         if (name == null) {
             outError[0] = tag + " does not specify android:name";
@@ -2277,6 +2290,11 @@
             outInfo.logo = logoVal;
         }
 
+        int bannerVal = sa.getResourceId(bannerRes, 0);
+        if (bannerVal != 0) {
+            outInfo.banner = bannerVal;
+        }
+
         TypedValue v = sa.peekValue(labelRes);
         if (v != null && (outInfo.labelRes=v.resourceId) == 0) {
             outInfo.nonLocalizedLabel = v.coerceToString();
@@ -2300,6 +2318,7 @@
                     com.android.internal.R.styleable.AndroidManifestActivity_label,
                     com.android.internal.R.styleable.AndroidManifestActivity_icon,
                     com.android.internal.R.styleable.AndroidManifestActivity_logo,
+                    com.android.internal.R.styleable.AndroidManifestActivity_banner,
                     mSeparateProcesses,
                     com.android.internal.R.styleable.AndroidManifestActivity_process,
                     com.android.internal.R.styleable.AndroidManifestActivity_description,
@@ -2426,6 +2445,12 @@
             a.info.flags |= ActivityInfo.FLAG_IMMERSIVE;
         }
 
+        if (sa.getBoolean(
+                com.android.internal.R.styleable.AndroidManifestActivity_allowEmbedded,
+                false)) {
+            a.info.flags |= ActivityInfo.FLAG_ALLOW_EMBEDDED;
+        }
+
         if (!receiver) {
             if (sa.getBoolean(
                     com.android.internal.R.styleable.AndroidManifestActivity_hardwareAccelerated,
@@ -2585,6 +2610,7 @@
                     com.android.internal.R.styleable.AndroidManifestActivityAlias_label,
                     com.android.internal.R.styleable.AndroidManifestActivityAlias_icon,
                     com.android.internal.R.styleable.AndroidManifestActivityAlias_logo,
+                    com.android.internal.R.styleable.AndroidManifestActivityAlias_banner,
                     mSeparateProcesses,
                     0,
                     com.android.internal.R.styleable.AndroidManifestActivityAlias_description,
@@ -2619,6 +2645,7 @@
         info.flags = target.info.flags;
         info.icon = target.info.icon;
         info.logo = target.info.logo;
+        info.banner = target.info.banner;
         info.labelRes = target.info.labelRes;
         info.nonLocalizedLabel = target.info.nonLocalizedLabel;
         info.launchMode = target.info.launchMode;
@@ -2732,6 +2759,7 @@
                     com.android.internal.R.styleable.AndroidManifestProvider_label,
                     com.android.internal.R.styleable.AndroidManifestProvider_icon,
                     com.android.internal.R.styleable.AndroidManifestProvider_logo,
+                    com.android.internal.R.styleable.AndroidManifestProvider_banner,
                     mSeparateProcesses,
                     com.android.internal.R.styleable.AndroidManifestProvider_process,
                     com.android.internal.R.styleable.AndroidManifestProvider_description,
@@ -3038,6 +3066,7 @@
                     com.android.internal.R.styleable.AndroidManifestService_label,
                     com.android.internal.R.styleable.AndroidManifestService_icon,
                     com.android.internal.R.styleable.AndroidManifestService_logo,
+                    com.android.internal.R.styleable.AndroidManifestService_banner,
                     mSeparateProcesses,
                     com.android.internal.R.styleable.AndroidManifestService_process,
                     com.android.internal.R.styleable.AndroidManifestService_description,
@@ -3335,6 +3364,9 @@
         outInfo.logo = sa.getResourceId(
                 com.android.internal.R.styleable.AndroidManifestIntentFilter_logo, 0);
 
+        outInfo.banner = sa.getResourceId(
+                com.android.internal.R.styleable.AndroidManifestIntentFilter_banner, 0);
+
         sa.recycle();
 
         int outerDepth = parser.getDepth();
@@ -3704,6 +3736,11 @@
                 outInfo.logo = logoVal;
             }
 
+            int bannerVal = args.sa.getResourceId(args.bannerRes, 0);
+            if (bannerVal != 0) {
+                outInfo.banner = bannerVal;
+            }
+
             TypedValue v = args.sa.peekValue(args.labelRes);
             if (v != null && (outInfo.labelRes=v.resourceId) == 0) {
                 outInfo.nonLocalizedLabel = v.coerceToString();
@@ -4128,6 +4165,7 @@
         public CharSequence nonLocalizedLabel;
         public int icon;
         public int logo;
+        public int banner;
         public int preferred;
     }
 
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index 48b6fca..a07fc97 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -440,6 +440,11 @@
      * <a href="{@docRoot}guide/topics/resources/providing-resources.html#UiModeQualifier">appliance</a>
      * resource qualifier. */
     public static final int UI_MODE_TYPE_APPLIANCE = 0x05;
+    /** Constant for {@link #uiMode}: a {@link #UI_MODE_TYPE_MASK}
+     * value that corresponds to the
+     * <a href="{@docRoot}guide/topics/resources/providing-resources.html#UiModeQualifier">watch</a>
+     * resource qualifier. */
+    public static final int UI_MODE_TYPE_WATCH = 0x06;
 
     /** Constant for {@link #uiMode}: bits that encode the night mode. */
     public static final int UI_MODE_NIGHT_MASK = 0x30;
@@ -462,8 +467,8 @@
      * <p>The {@link #UI_MODE_TYPE_MASK} bits define the overall ui mode of the
      * device. They may be one of {@link #UI_MODE_TYPE_UNDEFINED},
      * {@link #UI_MODE_TYPE_NORMAL}, {@link #UI_MODE_TYPE_DESK},
-     * {@link #UI_MODE_TYPE_CAR}, {@link #UI_MODE_TYPE_TELEVISION}, or
-     * {@link #UI_MODE_TYPE_APPLIANCE}.
+     * {@link #UI_MODE_TYPE_CAR}, {@link #UI_MODE_TYPE_TELEVISION},
+     * {@link #UI_MODE_TYPE_APPLIANCE}, or {@link #UI_MODE_TYPE_WATCH}.
      *
      * <p>The {@link #UI_MODE_NIGHT_MASK} defines whether the screen
      * is in a special mode. They may be one of {@link #UI_MODE_NIGHT_UNDEFINED},
@@ -700,6 +705,7 @@
             case UI_MODE_TYPE_CAR: sb.append(" car"); break;
             case UI_MODE_TYPE_TELEVISION: sb.append(" television"); break;
             case UI_MODE_TYPE_APPLIANCE: sb.append(" appliance"); break;
+            case UI_MODE_TYPE_WATCH: sb.append(" watch"); break;
             default: sb.append(" uimode="); sb.append(uiMode&UI_MODE_TYPE_MASK); break;
         }
         switch ((uiMode&UI_MODE_NIGHT_MASK)) {
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 3d9daca..7318652 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -1461,6 +1461,11 @@
 
         private final AssetManager mAssets;
         private final long mTheme;
+
+        // Needed by layoutlib.
+        /*package*/ long getNativeTheme() {
+            return mTheme;
+        }
     }
 
     /**
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index 60ccc61..433d5d1c 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -738,14 +738,16 @@
         File dir = file.getParentFile();
         if (dir != null) {
             final String prefix = file.getName() + "-mj";
-            final FileFilter filter = new FileFilter() {
+            File[] files = dir.listFiles(new FileFilter() {
                 @Override
                 public boolean accept(File candidate) {
                     return candidate.getName().startsWith(prefix);
                 }
-            };
-            for (File masterJournal : dir.listFiles(filter)) {
-                deleted |= masterJournal.delete();
+            });
+            if (files != null) {
+                for (File masterJournal : files) {
+                    deleted |= masterJournal.delete();
+                }
             }
         }
         return deleted;
diff --git a/core/java/android/hardware/Sensor.java b/core/java/android/hardware/Sensor.java
index 89a5819..ad5a753 100644
--- a/core/java/android/hardware/Sensor.java
+++ b/core/java/android/hardware/Sensor.java
@@ -38,6 +38,13 @@
     public static final int TYPE_ACCELEROMETER = 1;
 
     /**
+     * A constant string describing an accelerometer sensor type.
+     *
+     * @see #TYPE_ACCELEROMETER
+     */
+    public static final String STRING_TYPE_ACCELEROMETER = "android.sensor.accelerometer";
+
+    /**
      * A constant describing a magnetic field sensor type.
      * <p>See {@link android.hardware.SensorEvent#values SensorEvent.values}
      * for more details.
@@ -45,6 +52,13 @@
     public static final int TYPE_MAGNETIC_FIELD = 2;
 
     /**
+     * A constant string describing a magnetic field sensor type.
+     *
+     * @see #TYPE_MAGNETIC_FIELD
+     */
+    public static final String STRING_TYPE_MAGNETIC_FIELD = "android.sensor.magnetic_field";
+
+    /**
      * A constant describing an orientation sensor type.
      * <p>See {@link android.hardware.SensorEvent#values SensorEvent.values}
      * for more details.
@@ -55,24 +69,58 @@
     @Deprecated
     public static final int TYPE_ORIENTATION = 3;
 
-    /** A constant describing a gyroscope sensor type.
+    /**
+     * A constant string describing an orientation sensor type.
+     *
+     * @see #TYPE_ORIENTATION
+     * @deprecated use {@link android.hardware.SensorManager#getOrientation
+     *             SensorManager.getOrientation()} instead.
+     */
+    @Deprecated
+    public static final String STRING_TYPE_ORIENTATION = "android.sensor.orientation";
+
+    /**
+     * A constant describing a gyroscope sensor type.
      * <p>See {@link android.hardware.SensorEvent#values SensorEvent.values}
      * for more details. */
     public static final int TYPE_GYROSCOPE = 4;
 
     /**
+     * A constant string describing a gyroscope sensor type.
+     *
+     * @see #TYPE_GYROSCOPE
+     */
+    public static final String STRING_TYPE_GYROSCOPE = "android.sensor.gyroscope";
+
+    /**
      * A constant describing a light sensor type.
      * <p>See {@link android.hardware.SensorEvent#values SensorEvent.values}
      * for more details.
      */
     public static final int TYPE_LIGHT = 5;
 
-    /** A constant describing a pressure sensor type.
+    /**
+     * A constant string describing a light sensor type.
+     *
+     * @see #TYPE_LIGHT
+     */
+    public static final String STRING_TYPE_LIGHT = "android.sensor.light";
+
+    /**
+     * A constant describing a pressure sensor type.
      * <p>See {@link android.hardware.SensorEvent#values SensorEvent.values}
-     * for more details. */
+     * for more details.
+     */
     public static final int TYPE_PRESSURE = 6;
 
     /**
+     * A constant string describing a pressure sensor type.
+     *
+     * @see #TYPE_PRESSURE
+     */
+    public static final String STRING_TYPE_PRESSURE = "android.sensor.pressure";
+
+    /**
      * A constant describing a temperature sensor type
      *
      * @deprecated use
@@ -83,6 +131,17 @@
     public static final int TYPE_TEMPERATURE = 7;
 
     /**
+     * A constant string describing a temperature sensor type
+     *
+     * @see #TYPE_TEMPERATURE
+     * @deprecated use
+     *             {@link android.hardware.Sensor#STRING_TYPE_AMBIENT_TEMPERATURE
+     *             Sensor.STRING_TYPE_AMBIENT_TEMPERATURE} instead.
+     */
+    @Deprecated
+    public static final String STRING_TYPE_TEMPERATURE = "android.sensor.temperature";
+
+    /**
      * A constant describing a proximity sensor type.
      * <p>See {@link android.hardware.SensorEvent#values SensorEvent.values}
      * for more details.
@@ -90,6 +149,13 @@
     public static final int TYPE_PROXIMITY = 8;
 
     /**
+     * A constant string describing a proximity sensor type.
+     *
+     * @see #TYPE_PROXIMITY
+     */
+    public static final String STRING_TYPE_PROXIMITY = "android.sensor.proximity";
+
+    /**
      * A constant describing a gravity sensor type.
      * <p>See {@link android.hardware.SensorEvent#values SensorEvent.values}
      * for more details.
@@ -97,6 +163,13 @@
     public static final int TYPE_GRAVITY = 9;
 
     /**
+     * A constant string describing a gravity sensor type.
+     *
+     * @see #TYPE_GRAVITY
+     */
+    public static final String STRING_TYPE_GRAVITY = "android.sensor.gravity";
+
+    /**
      * A constant describing a linear acceleration sensor type.
      * <p>See {@link android.hardware.SensorEvent#values SensorEvent.values}
      * for more details.
@@ -104,6 +177,14 @@
     public static final int TYPE_LINEAR_ACCELERATION = 10;
 
     /**
+     * A constant string describing a linear acceleration sensor type.
+     *
+     * @see #TYPE_LINEAR_ACCELERATION
+     */
+    public static final String STRING_TYPE_LINEAR_ACCELERATION =
+        "android.sensor.linear_acceleration";
+
+    /**
      * A constant describing a rotation vector sensor type.
      * <p>See {@link android.hardware.SensorEvent#values SensorEvent.values}
      * for more details.
@@ -111,18 +192,42 @@
     public static final int TYPE_ROTATION_VECTOR = 11;
 
     /**
+     * A constant string describing a rotation vector sensor type.
+     *
+     * @see #TYPE_ROTATION_VECTOR
+     */
+    public static final String STRING_TYPE_ROTATION_VECTOR = "android.sensor.rotation_vector";
+
+    /**
      * A constant describing a relative humidity sensor type.
      * <p>See {@link android.hardware.SensorEvent#values SensorEvent.values}
      * for more details.
      */
     public static final int TYPE_RELATIVE_HUMIDITY = 12;
 
-    /** A constant describing an ambient temperature sensor type.
+    /**
+     * A constant string describing a relative humidity sensor type
+     *
+     * @see #TYPE_RELATIVE_HUMIDITY
+     */
+    public static final String STRING_TYPE_RELATIVE_HUMIDITY = "android.sensor.relative_humidity";
+
+    /**
+     * A constant describing an ambient temperature sensor type.
      * <p>See {@link android.hardware.SensorEvent#values SensorEvent.values}
-     * for more details. */
+     * for more details.
+     */
     public static final int TYPE_AMBIENT_TEMPERATURE = 13;
 
     /**
+     * A constant string describing an ambient temperature sensor type.
+     *
+     * @see #TYPE_AMBIENT_TEMPERATURE
+     */
+    public static final String STRING_TYPE_AMBIENT_TEMPERATURE =
+        "android.sensor.ambient_temperature";
+
+    /**
      * A constant describing an uncalibrated magnetic field sensor type.
      * <p>
      * Similar to {@link #TYPE_MAGNETIC_FIELD} but the hard iron calibration (device calibration
@@ -139,6 +244,13 @@
      * details.
      */
     public static final int TYPE_MAGNETIC_FIELD_UNCALIBRATED = 14;
+    /**
+     * A constant string describing an uncalibrated magnetic field sensor type.
+     *
+     * @see #TYPE_MAGNETIC_FIELD_UNCALIBRATED
+     */
+    public static final String STRING_TYPE_MAGNETIC_FIELD_UNCALIBRATED =
+        "android.sensor.magnetic_field_uncalibrated";
 
     /**
      * A constant describing an uncalibrated rotation vector sensor type.
@@ -156,10 +268,17 @@
      * <p>See {@link android.hardware.SensorEvent#values SensorEvent.values} for more
      * details.
      */
-
     public static final int TYPE_GAME_ROTATION_VECTOR = 15;
 
     /**
+     * A constant string describing an uncalibrated rotation vector sensor type.
+     *
+     * @see #TYPE_GAME_ROTATION_VECTOR
+     */
+    public static final String STRING_TYPE_GAME_ROTATION_VECTOR =
+        "android.sensor.game_rotation_vector";
+
+    /**
      * A constant describing an uncalibrated gyroscope sensor type.
      * <p>Similar to {@link #TYPE_GYROSCOPE} but no gyro-drift compensation has been performed
      * to adjust the given sensor values. However, such gyro-drift bias values
@@ -174,6 +293,14 @@
     public static final int TYPE_GYROSCOPE_UNCALIBRATED = 16;
 
     /**
+     * A constant string describing an uncalibrated gyroscope sensor type.
+     *
+     * @see #TYPE_GYROSCOPE_UNCALIBRATED
+     */
+    public static final String STRING_TYPE_GYROSCOPE_UNCALIBRATED =
+        "android.sensor.gyroscope_uncalibrated";
+
+    /**
      * A constant describing a significant motion trigger sensor.
      * <p>
      * It triggers when an event occurs and then automatically disables
@@ -186,6 +313,14 @@
     public static final int TYPE_SIGNIFICANT_MOTION = 17;
 
     /**
+     * A constant string describing a significant motion trigger sensor.
+     *
+     * @see #TYPE_SIGNIFICANT_MOTION
+     */
+    public static final String STRING_TYPE_SIGNIFICANT_MOTION =
+        "android.sensor.significant_motion";
+
+    /**
      * A constant describing a step detector sensor.
      * <p>
      * A sensor of this type triggers an event each time a step is taken by the user. The only
@@ -198,6 +333,13 @@
     public static final int TYPE_STEP_DETECTOR = 18;
 
     /**
+     * A constant string describing a step detector sensor.
+     *
+     * @see #TYPE_STEP_DETECTOR
+     */
+    public static final String STRING_TYPE_STEP_DETECTOR = "android.sensor.step_detector";
+
+    /**
      * A constant describing a step counter sensor.
      * <p>
      * A sensor of this type returns the number of steps taken by the user since the last reboot
@@ -211,7 +353,14 @@
     public static final int TYPE_STEP_COUNTER = 19;
 
     /**
-     * A constant describing the geo-magnetic rotation vector.
+     * A constant string describing a step counter sensor.
+     *
+     * @see #TYPE_STEP_COUNTER
+     */
+    public static final String STRING_TYPE_STEP_COUNTER = "android.sensor.step_counter";
+
+    /**
+     * A constant describing a geo-magnetic rotation vector.
      * <p>
      * Similar to {@link #TYPE_ROTATION_VECTOR}, but using a magnetometer instead of using a
      * gyroscope. This sensor uses lower power than the other rotation vectors, because it doesn't
@@ -222,6 +371,32 @@
     public static final int TYPE_GEOMAGNETIC_ROTATION_VECTOR = 20;
 
     /**
+     * A constant string describing a geo-magnetic rotation vector.
+     *
+     * @see #TYPE_GEOMAGNETIC_ROTATION_VECTOR
+     */
+    public static final String STRING_TYPE_GEOMAGNETIC_ROTATION_VECTOR =
+        "android.sensor.geomagnetic_rotation_vector";
+
+    /**
+     * A constant describing a heart rate monitor.
+     * <p>
+     * A sensor that measures the heart rate in beats per minute.
+     * <p>
+     * value[0] represents the beats per minute when the measurement was taken.
+     * value[0] is 0 if the heart rate monitor could not measure the rate or the
+     * rate is 0 beat per minute.
+     */
+    public static final int TYPE_HEART_RATE = 21;
+
+    /**
+     * A constant string describing a heart rate monitor.
+     *
+     * @see #TYPE_HEART_RATE
+     */
+    public static final String STRING_TYPE_HEART_RATE = "android.sensor.heart_rate";
+
+    /**
      * A constant describing all sensor types.
      */
     public static final int TYPE_ALL = -1;
@@ -265,7 +440,8 @@
             // added post 4.3
             REPORTING_MODE_ON_CHANGE,  1, // SENSOR_TYPE_STEP_DETECTOR
             REPORTING_MODE_ON_CHANGE,  1, // SENSOR_TYPE_STEP_COUNTER
-            REPORTING_MODE_CONTINUOUS, 5  // SENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR
+            REPORTING_MODE_CONTINUOUS, 5, // SENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR
+            REPORTING_MODE_ON_CHANGE, 1  // SENSOR_TYPE_HEART_RATE_MONITOR
     };
 
     static int getReportingMode(Sensor sensor) {
@@ -321,6 +497,8 @@
     private int     mMinDelay;
     private int     mFifoReservedEventCount;
     private int     mFifoMaxEventCount;
+    private String  mStringType;
+    private String  mRequiredPermission;
 
     Sensor() {
     }
@@ -401,6 +579,21 @@
         return mFifoMaxEventCount;
     }
 
+    /**
+     * @return The type of this sensor as a string.
+     */
+    public String getStringType() {
+        return mStringType;
+    }
+
+    /**
+     * @return The permission required to access this sensor. If empty, no permission is required.
+     * @hide
+     */
+    public String getRequiredPermission() {
+        return mRequiredPermission;
+    }
+
     /** @hide */
     public int getHandle() {
         return mHandle;
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index 093e0e9..79673b3 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -115,6 +115,7 @@
       * </p>
      *
      * @see #createVirtualDisplay
+     * @see #VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY
      */
     public static final int VIRTUAL_DISPLAY_FLAG_PUBLIC = 1 << 0;
 
@@ -171,6 +172,22 @@
      */
     public static final int VIRTUAL_DISPLAY_FLAG_SECURE = 1 << 2;
 
+    /**
+     * Virtual display flag: Only show this display's own content; do not mirror
+     * the content of another display.
+     *
+     * <p>
+     * This flag is used in conjunction with {@link #VIRTUAL_DISPLAY_FLAG_PUBLIC}.
+     * Ordinarily public virtual displays will automatically mirror the content of the
+     * default display if they have no windows of their own.  When this flag is
+     * specified, the virtual display will only ever show its own content and
+     * will be blanked instead if it has no windows.
+     * </p>
+     *
+     * @see #createVirtualDisplay
+     */
+    public static final int VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY = 1 << 3;
+
     /** @hide */
     public DisplayManager(Context context) {
         mContext = context;
@@ -420,6 +437,14 @@
      * The behavior of the virtual display depends on the flags that are provided
      * to this method.  By default, virtual displays are created to be private,
      * non-presentation and unsecure.  Permissions may be required to use certain flags.
+     * </p><p>
+     * As of {@link android.os.Build.VERSION_CODES#KITKAT_WATCH}, the surface may
+     * be attached or detached dynamically using {@link VirtualDisplay#setSurface}.
+     * Previously, the surface had to be non-null when {@link #createVirtualDisplay}
+     * was called and could not be changed for the lifetime of the display.
+     * </p><p>
+     * Detaching the surface that backs a virtual display has a similar effect to
+     * turning off the screen.
      * </p>
      *
      * @param name The name of the virtual display, must be non-empty.
@@ -427,10 +452,10 @@
      * @param height The height of the virtual display in pixels, must be greater than 0.
      * @param densityDpi The density of the virtual display in dpi, must be greater than 0.
      * @param surface The surface to which the content of the virtual display should
-     * be rendered, must be non-null.
+     * be rendered, or null if there is none initially.
      * @param flags A combination of virtual display flags:
-     * {@link #VIRTUAL_DISPLAY_FLAG_PUBLIC}, {@link #VIRTUAL_DISPLAY_FLAG_PRESENTATION}
-     * or {@link #VIRTUAL_DISPLAY_FLAG_SECURE}.
+     * {@link #VIRTUAL_DISPLAY_FLAG_PUBLIC}, {@link #VIRTUAL_DISPLAY_FLAG_PRESENTATION},
+     * {@link #VIRTUAL_DISPLAY_FLAG_SECURE}, or {@link #VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY}.
      * @return The newly created virtual display, or null if the application could
      * not create the virtual display.
      *
diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
index 3417430..a8d55e8 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -377,9 +377,6 @@
             throw new IllegalArgumentException("width, height, and densityDpi must be "
                     + "greater than 0");
         }
-        if (surface == null) {
-            throw new IllegalArgumentException("surface must not be null");
-        }
 
         Binder token = new Binder();
         int displayId;
@@ -404,7 +401,15 @@
             }
             return null;
         }
-        return new VirtualDisplay(this, display, token);
+        return new VirtualDisplay(this, display, token, surface);
+    }
+
+    public void setVirtualDisplaySurface(IBinder token, Surface surface) {
+        try {
+            mDm.setVirtualDisplaySurface(token, surface);
+        } catch (RemoteException ex) {
+            Log.w(TAG, "Failed to set virtual display surface.", ex);
+        }
     }
 
     public void releaseVirtualDisplay(IBinder token) {
diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java
new file mode 100644
index 0000000..cec90cd
--- /dev/null
+++ b/core/java/android/hardware/display/DisplayManagerInternal.java
@@ -0,0 +1,261 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.display;
+
+import android.hardware.SensorManager;
+import android.os.Handler;
+import android.os.PowerManager;
+import android.view.DisplayInfo;
+
+/**
+ * Display manager local system service interface.
+ *
+ * @hide Only for use within the system server.
+ */
+public abstract class DisplayManagerInternal {
+    /**
+     * Called by the power manager to initialize power management facilities.
+     */
+    public abstract void initPowerManagement(DisplayPowerCallbacks callbacks,
+            Handler handler, SensorManager sensorManager);
+
+    /**
+     * Called by the power manager to request a new power state.
+     * <p>
+     * The display power controller makes a copy of the provided object and then
+     * begins adjusting the power state to match what was requested.
+     * </p>
+     *
+     * @param request The requested power state.
+     * @param waitForNegativeProximity If true, issues a request to wait for
+     * negative proximity before turning the screen back on, assuming the screen
+     * was turned off by the proximity sensor.
+     * @return True if display is ready, false if there are important changes that must
+     * be made asynchronously (such as turning the screen on), in which case the caller
+     * should grab a wake lock, watch for {@link DisplayPowerCallbacks#onStateChanged()}
+     * then try the request again later until the state converges.
+     */
+    public abstract boolean requestPowerState(DisplayPowerRequest request,
+            boolean waitForNegativeProximity);
+
+    /**
+     * Returns true if the proximity sensor screen-off function is available.
+     */
+    public abstract boolean isProximitySensorAvailable();
+
+    /**
+     * Returns information about the specified logical display.
+     *
+     * @param displayId The logical display id.
+     * @return The logical display info, or null if the display does not exist.  The
+     * returned object must be treated as immutable.
+     */
+    public abstract DisplayInfo getDisplayInfo(int displayId);
+
+    /**
+     * Registers a display transaction listener to provide the client a chance to
+     * update its surfaces within the same transaction as any display layout updates.
+     *
+     * @param listener The listener to register.
+     */
+    public abstract void registerDisplayTransactionListener(DisplayTransactionListener listener);
+
+    /**
+     * Unregisters a display transaction listener to provide the client a chance to
+     * update its surfaces within the same transaction as any display layout updates.
+     *
+     * @param listener The listener to unregister.
+     */
+    public abstract void unregisterDisplayTransactionListener(DisplayTransactionListener listener);
+
+    /**
+     * Overrides the display information of a particular logical display.
+     * This is used by the window manager to control the size and characteristics
+     * of the default display.  It is expected to apply the requested change
+     * to the display information synchronously so that applications will immediately
+     * observe the new state.
+     *
+     * NOTE: This method must be the only entry point by which the window manager
+     * influences the logical configuration of displays.
+     *
+     * @param displayId The logical display id.
+     * @param info The new data to be stored.
+     */
+    public abstract void setDisplayInfoOverrideFromWindowManager(
+            int displayId, DisplayInfo info);
+
+    /**
+     * Called by the window manager to perform traversals while holding a
+     * surface flinger transaction.
+     */
+    public abstract void performTraversalInTransactionFromWindowManager();
+
+    /**
+     * Tells the display manager whether there is interesting unique content on the
+     * specified logical display.  This is used to control automatic mirroring.
+     * <p>
+     * If the display has unique content, then the display manager arranges for it
+     * to be presented on a physical display if appropriate.  Otherwise, the display manager
+     * may choose to make the physical display mirror some other logical display.
+     * </p>
+     *
+     * @param displayId The logical display id to update.
+     * @param hasContent True if the logical display has content.
+     * @param inTraversal True if called from WindowManagerService during a window traversal
+     * prior to call to performTraversalInTransactionFromWindowManager.
+     */
+    public abstract void setDisplayHasContent(int displayId, boolean hasContent,
+            boolean inTraversal);
+
+    /**
+     * Describes the requested power state of the display.
+     *
+     * This object is intended to describe the general characteristics of the
+     * power state, such as whether the screen should be on or off and the current
+     * brightness controls leaving the DisplayPowerController to manage the
+     * details of how the transitions between states should occur.  The goal is for
+     * the PowerManagerService to focus on the global power state and not
+     * have to micro-manage screen off animations, auto-brightness and other effects.
+     */
+    public static final class DisplayPowerRequest {
+        public static final int SCREEN_STATE_OFF = 0;
+        public static final int SCREEN_STATE_DOZE = 1;
+        public static final int SCREEN_STATE_DIM = 2;
+        public static final int SCREEN_STATE_BRIGHT = 3;
+
+        // The requested minimum screen power state: off, doze, dim or bright.
+        public int screenState;
+
+        // If true, the proximity sensor overrides the screen state when an object is
+        // nearby, turning it off temporarily until the object is moved away.
+        public boolean useProximitySensor;
+
+        // The desired screen brightness in the range 0 (minimum / off) to 255 (brightest).
+        // The display power controller may choose to clamp the brightness.
+        // When auto-brightness is enabled, this field should specify a nominal default
+        // value to use while waiting for the light sensor to report enough data.
+        public int screenBrightness;
+
+        // The screen auto-brightness adjustment factor in the range -1 (dimmer) to 1 (brighter).
+        public float screenAutoBrightnessAdjustment;
+
+        // If true, enables automatic brightness control.
+        public boolean useAutoBrightness;
+
+        // If true, prevents the screen from completely turning on if it is currently off.
+        // The display does not enter a "ready" state if this flag is true and screen on is
+        // blocked.  The window manager policy blocks screen on while it prepares the keyguard to
+        // prevent the user from seeing intermediate updates.
+        //
+        // Technically, we may not block the screen itself from turning on (because that introduces
+        // extra unnecessary latency) but we do prevent content on screen from becoming
+        // visible to the user.
+        public boolean blockScreenOn;
+
+        public DisplayPowerRequest() {
+            screenState = SCREEN_STATE_BRIGHT;
+            useProximitySensor = false;
+            screenBrightness = PowerManager.BRIGHTNESS_ON;
+            screenAutoBrightnessAdjustment = 0.0f;
+            useAutoBrightness = false;
+            blockScreenOn = false;
+        }
+
+        public DisplayPowerRequest(DisplayPowerRequest other) {
+            copyFrom(other);
+        }
+
+        // Returns true if we want the screen on in any mode, including doze.
+        public boolean wantScreenOnAny() {
+            return screenState != SCREEN_STATE_OFF;
+        }
+
+        // Returns true if we want the screen on in a normal mode, excluding doze.
+        // This is usually what we want to tell the rest of the system.  For compatibility
+        // reasons, we pretend the screen is off when dozing.
+        public boolean wantScreenOnNormal() {
+            return screenState == SCREEN_STATE_DIM || screenState == SCREEN_STATE_BRIGHT;
+        }
+
+        public boolean wantLightSensorEnabled() {
+            // Specifically, we don't want the light sensor while dozing.
+            return useAutoBrightness && wantScreenOnNormal();
+        }
+
+        public void copyFrom(DisplayPowerRequest other) {
+            screenState = other.screenState;
+            useProximitySensor = other.useProximitySensor;
+            screenBrightness = other.screenBrightness;
+            screenAutoBrightnessAdjustment = other.screenAutoBrightnessAdjustment;
+            useAutoBrightness = other.useAutoBrightness;
+            blockScreenOn = other.blockScreenOn;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            return o instanceof DisplayPowerRequest
+                    && equals((DisplayPowerRequest)o);
+        }
+
+        public boolean equals(DisplayPowerRequest other) {
+            return other != null
+                    && screenState == other.screenState
+                    && useProximitySensor == other.useProximitySensor
+                    && screenBrightness == other.screenBrightness
+                    && screenAutoBrightnessAdjustment == other.screenAutoBrightnessAdjustment
+                    && useAutoBrightness == other.useAutoBrightness
+                    && blockScreenOn == other.blockScreenOn;
+        }
+
+        @Override
+        public int hashCode() {
+            return 0; // don't care
+        }
+
+        @Override
+        public String toString() {
+            return "screenState=" + screenState
+                    + ", useProximitySensor=" + useProximitySensor
+                    + ", screenBrightness=" + screenBrightness
+                    + ", screenAutoBrightnessAdjustment=" + screenAutoBrightnessAdjustment
+                    + ", useAutoBrightness=" + useAutoBrightness
+                    + ", blockScreenOn=" + blockScreenOn;
+        }
+    }
+
+    /**
+     * Asynchronous callbacks from the power controller to the power manager service.
+     */
+    public interface DisplayPowerCallbacks {
+        void onStateChanged();
+        void onProximityPositive();
+        void onProximityNegative();
+        void onDisplayStateChange(int state); // one of the Display state constants
+
+        void acquireSuspendBlocker();
+        void releaseSuspendBlocker();
+    }
+
+    /**
+     * Called within a Surface transaction whenever the size or orientation of a
+     * display may have changed.  Provides an opportunity for the client to
+     * update the position of its surfaces as part of the same transaction.
+     */
+    public interface DisplayTransactionListener {
+        void onDisplayTransaction();
+    }
+}
diff --git a/services/java/com/android/server/display/DisplayViewport.java b/core/java/android/hardware/display/DisplayViewport.java
similarity index 96%
rename from services/java/com/android/server/display/DisplayViewport.java
rename to core/java/android/hardware/display/DisplayViewport.java
index 5080556..c2d498b 100644
--- a/services/java/com/android/server/display/DisplayViewport.java
+++ b/core/java/android/hardware/display/DisplayViewport.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.display;
+package android.hardware.display;
 
 import android.graphics.Rect;
 
@@ -25,6 +25,8 @@
  * This information is used by the input system to translate touch input from
  * physical display coordinates into logical display coordinates.
  * </p>
+ *
+ * @hide Only for use within the system server.
  */
 public final class DisplayViewport {
     // True if this viewport is valid.
diff --git a/core/java/android/hardware/display/IDisplayManager.aidl b/core/java/android/hardware/display/IDisplayManager.aidl
index 68eb13f..23c58c8 100644
--- a/core/java/android/hardware/display/IDisplayManager.aidl
+++ b/core/java/android/hardware/display/IDisplayManager.aidl
@@ -63,5 +63,8 @@
             String name, int width, int height, int densityDpi, in Surface surface, int flags);
 
     // No permissions required but must be same Uid as the creator.
+    void setVirtualDisplaySurface(in IBinder token, in Surface surface);
+
+    // No permissions required but must be same Uid as the creator.
     void releaseVirtualDisplay(in IBinder token);
 }
diff --git a/core/java/android/hardware/display/VirtualDisplay.java b/core/java/android/hardware/display/VirtualDisplay.java
index 01e5bac..691d6a0 100644
--- a/core/java/android/hardware/display/VirtualDisplay.java
+++ b/core/java/android/hardware/display/VirtualDisplay.java
@@ -17,15 +17,18 @@
 
 import android.os.IBinder;
 import android.view.Display;
+import android.view.Surface;
 
 /**
  * Represents a virtual display. The content of a virtual display is rendered to a
  * {@link android.view.Surface} that you must provide to {@link DisplayManager#createVirtualDisplay
  * createVirtualDisplay()}.
- * <p>Because a virtual display renders to a surface provided by the application, it will be
+ * <p>
+ * Because a virtual display renders to a surface provided by the application, it will be
  * released automatically when the process terminates and all remaining windows on it will
- * be forcibly removed. However, you should also explicitly call {@link #release} when you're
- * done with it.
+ * be forcibly removed.  However, you should also explicitly call {@link #release} when
+ * you're done with it.
+ * </p>
  *
  * @see DisplayManager#createVirtualDisplay
  */
@@ -33,11 +36,14 @@
     private final DisplayManagerGlobal mGlobal;
     private final Display mDisplay;
     private IBinder mToken;
+    private Surface mSurface;
 
-    VirtualDisplay(DisplayManagerGlobal global, Display display, IBinder token) {
+    VirtualDisplay(DisplayManagerGlobal global, Display display, IBinder token,
+            Surface surface) {
         mGlobal = global;
         mDisplay = display;
         mToken = token;
+        mSurface = surface;
     }
 
     /**
@@ -48,6 +54,32 @@
     }
 
     /**
+     * Gets the surface that backs the virtual display.
+     */
+    public Surface getSurface() {
+        return mSurface;
+    }
+
+    /**
+     * Sets the surface that backs the virtual display.
+     * <p>
+     * Detaching the surface that backs a virtual display has a similar effect to
+     * turning off the screen.
+     * </p><p>
+     * It is still the caller's responsibility to destroy the surface after it has
+     * been detached.
+     * </p>
+     *
+     * @param surface The surface to set, or null to detach the surface from the virtual display.
+     */
+    public void setSurface(Surface surface) {
+        if (mSurface != surface) {
+            mGlobal.setVirtualDisplaySurface(mToken, surface);
+            mSurface = surface;
+        }
+    }
+
+    /**
      * Releases the virtual display and destroys its underlying surface.
      * <p>
      * All remaining windows on the virtual display will be forcibly removed
@@ -63,6 +95,7 @@
 
     @Override
     public String toString() {
-        return "VirtualDisplay{display=" + mDisplay + ", token=" + mToken + "}";
+        return "VirtualDisplay{display=" + mDisplay + ", token=" + mToken
+                + ", surface=" + mSurface + "}";
     }
 }
diff --git a/core/java/android/hardware/hdmi/HdmiCec.java b/core/java/android/hardware/hdmi/HdmiCec.java
new file mode 100644
index 0000000..5c2612f
--- /dev/null
+++ b/core/java/android/hardware/hdmi/HdmiCec.java
@@ -0,0 +1,259 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.hdmi;
+
+/**
+ * Defines constants and utility methods related to HDMI-CEC protocol.
+ *
+ * @hide
+ */
+public final class HdmiCec {
+
+    /** TV device type. */
+    public static final int DEVICE_TV = 0;
+
+    /** Recording device type. */
+    public static final int DEVICE_RECORDER = 1;
+
+    /** Device type reserved for future usage. */
+    public static final int DEVICE_RESERVED = 2;
+
+    /** Tuner device type. */
+    public static final int DEVICE_TUNER = 3;
+
+    /** Playback device type. */
+    public static final int DEVICE_PLAYBACK = 4;
+
+    /** Audio system device type. */
+    public static final int DEVICE_AUDIO_SYSTEM = 5;
+
+    // Value indicating the device is not an active source.
+    public static final int DEVICE_INACTIVE = -1;
+
+    /** Logical address for TV */
+    public static final int ADDR_TV = 0;
+
+    /** Logical address for recorder 1 */
+    public static final int ADDR_RECORDER_1 = 1;
+
+    /** Logical address for recorder 2 */
+    public static final int ADDR_RECORDER_2 = 2;
+
+    /** Logical address for tuner 1 */
+    public static final int ADDR_TUNER_1 = 3;
+
+    /** Logical address for playback 1 */
+    public static final int ADDR_PLAYBACK_1 = 4;
+
+    /** Logical address for audio system */
+    public static final int ADDR_AUDIO_SYSTEM = 5;
+
+    /** Logical address for tuner 2 */
+    public static final int ADDR_TUNER_2 = 6;
+
+    /** Logical address for tuner 3 */
+    public static final int ADDR_TUNER_3 = 7;
+
+    /** Logical address for playback 2 */
+    public static final int ADDR_PLAYBACK_2 = 8;
+
+    /** Logical address for recorder 3 */
+    public static final int ADDR_RECORDER_3 = 9;
+
+    /** Logical address for tuner 4 */
+    public static final int ADDR_TUNER_4 = 10;
+
+    /** Logical address for playback 3 */
+    public static final int ADDR_PLAYBACK_3 = 11;
+
+    /** Logical address reserved for future usage */
+    public static final int ADDR_RESERVED_1 = 12;
+
+    /** Logical address reserved for future usage */
+    public static final int ADDR_RESERVED_2 = 13;
+
+    /** Logical address for TV other than the one assigned with {@link #ADDR_TV} */
+    public static final int ADDR_FREE_USE = 14;
+
+    /** Logical address for devices to which address cannot be allocated */
+    public static final int ADDR_UNREGISTERED = 15;
+
+    /** Logical address used in the destination address field for broadcast messages */
+    public static final int ADDR_BROADCAST = 15;
+
+    /** Logical address used to indicate it is not initialized or invalid. */
+    public static final int ADDR_INVALID = -1;
+
+    // TODO: Complete the list of CEC messages definition.
+    public static final int MESSAGE_FEATURE_ABORT = 0x00;
+    public static final int MESSAGE_IMAGE_VIEW_ON = 0x04;
+    public static final int MESSAGE_TUNER_STEP_INCREMENT = 0x05;
+    public static final int MESSAGE_TUNER_STEP_DECREMENT = 0x06;
+    public static final int MESSAGE_TUNER_DEVICE_STATUS = 0x07;
+    public static final int MESSAGE_GIVE_TUNER_DEVICE_STATUS = 0x08;
+    public static final int MESSAGE_RECORD_ON = 0x09;
+    public static final int MESSAGE_RECORD_STATUS = 0x0A;
+    public static final int MESSAGE_RECORD_OFF = 0x0B;
+    public static final int MESSAGE_TEXT_VIEW_ON = 0x0D;
+    public static final int MESSAGE_RECORD_TV_SCREEN = 0x0F;
+    public static final int MESSAGE_GIVE_DECK_STATUS = 0x1A;
+    public static final int MESSAGE_DECK_STATUS = 0x1B;
+    public static final int MESSAGE_SET_MENU_LANGUAGE = 0x32;
+    public static final int MESSAGE_CLEAR_ANALOG_TIMER = 0x33;
+    public static final int MESSAGE_SET_ANALOG_TIMER = 0x34;
+    public static final int MESSAGE_TIMER_STATUS = 0x35;
+    public static final int MESSAGE_STANDBY = 0x36;
+    public static final int MESSAGE_PLAY = 0x41;
+    public static final int MESSAGE_DECK_CONTROL = 0x42;
+    public static final int MESSAGE_TIMER_CLEARED_STATUS = 0x043;
+    public static final int MESSAGE_USER_CONTROL_PRESSED = 0x44;
+    public static final int MESSAGE_USER_CONTROL_RELEASED = 0x45;
+    public static final int MESSAGE_GET_OSD_NAME = 0x46;
+    public static final int MESSAGE_SET_OSD_NAME = 0x47;
+    public static final int MESSAGE_SET_OSD_STRING = 0x64;
+    public static final int MESSAGE_SET_TIMER_PROGRAM_TITLE = 0x67;
+    public static final int MESSAGE_SYSTEM_AUDIO_MODE_REQUEST = 0x70;
+    public static final int MESSAGE_GIVE_AUDIO_STATUS = 0x71;
+    public static final int MESSAGE_SET_SYSTEM_AUDIO_MODE = 0x72;
+    public static final int MESSAGE_REPORT_AUDIO_STATUS = 0x7A;
+    public static final int MESSAGE_GIVE_SYSTEM_AUDIO_MODE_STATUS = 0x7D;
+    public static final int MESSAGE_SYSTEM_AUDIO_MODE_STATUS = 0x7E;
+    public static final int MESSAGE_ROUTING_CHANGE = 0x80;
+    public static final int MESSAGE_ROUTING_INFORMATION = 0x81;
+    public static final int MESSAGE_ACTIVE_SOURCE = 0x82;
+    public static final int MESSAGE_GIVE_PHYSICAL_ADDRESS = 0x83;
+    public static final int MESSAGE_REPORT_PHYSICAL_ADDRESS = 0x84;
+    public static final int MESSAGE_REQUEST_ACTIVE_SOURCE = 0x85;
+    public static final int MESSAGE_SET_STREAM_PATH = 0x86;
+    public static final int MESSAGE_DEVICE_VENDOR_ID = 0x87;
+    public static final int MESSAGE_VENDOR_COMMAND = 0x89;
+    public static final int MESSAGE_VENDOR_REMOTE_BUTTON_DOWN = 0x8A;
+    public static final int MESSAGE_VENDOR_REMOTE_BUTTON_UP = 0x8B;
+    public static final int MESSAGE_GIVE_DEVICE_VENDOR_ID = 0x8C;
+    public static final int MESSAGE_MENU_REQUEST = 0x8D;
+    public static final int MESSAGE_MENU_STATUS = 0x8E;
+    public static final int MESSAGE_GIVE_DEVICE_POWER_STATUS = 0x8F;
+    public static final int MESSAGE_REPORT_POWER_STATUS = 0x90;
+    public static final int MESSAGE_GET_MENU_LANGUAGE = 0x91;
+    public static final int MESSAGE_SELECT_ANALOG_SERVICE = 0x92;
+    public static final int MESSAGE_SELECT_DIGITAL_SERVICE = 0x93;
+    public static final int MESSAGE_SET_DIGITAL_TIMER = 0x97;
+    public static final int MESSAGE_CLEAR_DIGITAL_TIMER = 0x99;
+    public static final int MESSAGE_SET_AUDIO_RATE = 0x9A;
+    public static final int MESSAGE_INACTIVE_SOURCE = 0x9D;
+    public static final int MESSAGE_CEC_VERSION = 0x9E;
+    public static final int MESSAGE_GET_CEC_VERSION = 0x9F;
+    public static final int MESSAGE_VENDOR_COMMAND_WITH_ID = 0xA0;
+    public static final int MESSAGE_CLEAR_EXTERNAL_TIMER = 0xA1;
+    public static final int MESSAGE_SET_EXTERNAL_TIMER = 0xA2;
+    public static final int MESSAGE_ABORT = 0xFF;
+
+    public static final int POWER_STATUS_UNKNOWN = -1;
+    public static final int POWER_STATUS_ON = 0;
+    public static final int POWER_STATUS_STANDBY = 1;
+    public static final int POWER_TRANSIENT_TO_ON = 2;
+    public static final int POWER_TRANSIENT_TO_STANDBY = 3;
+
+    private static final int[] ADDRESS_TO_TYPE = {
+        DEVICE_TV,  // ADDR_TV
+        DEVICE_RECORDER,  // ADDR_RECORDER_1
+        DEVICE_RECORDER,  // ADDR_RECORDER_2
+        DEVICE_TUNER,  // ADDR_TUNER_1
+        DEVICE_PLAYBACK,  // ADDR_PLAYBACK_1
+        DEVICE_AUDIO_SYSTEM,  // ADDR_AUDIO_SYSTEM
+        DEVICE_TUNER,  // ADDR_TUNER_2
+        DEVICE_TUNER,  // ADDR_TUNER_3
+        DEVICE_PLAYBACK,  // ADDR_PLAYBACK_2
+        DEVICE_RECORDER,  // ADDR_RECORDER_3
+        DEVICE_TUNER,  // ADDR_TUNER_4
+        DEVICE_PLAYBACK,  // ADDR_PLAYBACK_3
+    };
+
+    private static final String[] DEFAULT_NAMES = {
+        "TV",
+        "Recorder_1",
+        "Recorder_2",
+        "Tuner_1",
+        "Playback_1",
+        "AudioSystem",
+        "Tuner_2",
+        "Tuner_3",
+        "Playback_2",
+        "Recorder_3",
+        "Tuner_4",
+        "Playback_3",
+    };
+
+    private HdmiCec() { }  // Prevents instantiation.
+
+    /**
+     * Check if the given type is valid. A valid type is one of the actual
+     * logical device types defined in the standard ({@link #DEVICE_TV},
+     * {@link #DEVICE_PLAYBACK}, {@link #DEVICE_TUNER}, {@link #DEVICE_RECORDER},
+     * and {@link #DEVICE_AUDIO_SYSTEM}).
+     *
+     * @param type device type
+     * @return true if the given type is valid
+     */
+    public static boolean isValidType(int type) {
+        return (DEVICE_TV <= type && type <= DEVICE_AUDIO_SYSTEM)
+                && type != DEVICE_RESERVED;
+    }
+
+    /**
+     * Check if the given logical address is valid. A logical address is valid
+     * if it is one allocated for an actual device which allows communication
+     * with other logical devices.
+     *
+     * @param address logical address
+     * @return true if the given address is valid
+     */
+    public static boolean isValidAddress(int address) {
+        // TODO: We leave out the address 'free use(14)' for now. Check this later
+        //       again to make sure it is a valid address for communication.
+        return (ADDR_TV <= address && address <= ADDR_PLAYBACK_3);
+    }
+
+    /**
+     * Return the device type for the given logical address.
+     *
+     * @param address logical address
+     * @return device type for the given logical address; DEVICE_INACTIVE
+     *         if the address is not valid.
+     */
+    public static int getTypeFromAddress(int address) {
+        if (isValidAddress(address)) {
+            return ADDRESS_TO_TYPE[address];
+        }
+        return DEVICE_INACTIVE;
+    }
+
+    /**
+     * Return the default device name for a logical address. This is the name
+     * by which the logical device is known to others until a name is
+     * set explicitly using HdmiCecService.setOsdName.
+     *
+     * @param address logical address
+     * @return default device name; empty string if the address is not valid
+     */
+    public static String getDefaultDeviceName(int address) {
+        if (isValidAddress(address)) {
+            return DEFAULT_NAMES[address];
+        }
+        return "";
+    }
+}
diff --git a/core/java/android/hardware/hdmi/HdmiCecClient.java b/core/java/android/hardware/hdmi/HdmiCecClient.java
new file mode 100644
index 0000000..d8833d9
--- /dev/null
+++ b/core/java/android/hardware/hdmi/HdmiCecClient.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.hdmi;
+
+import android.os.IBinder;
+import android.os.RemoteException;
+
+import android.util.Log;
+
+/**
+ * HdmiCecClient is used to control HDMI-CEC logical device instance in the system.
+ * It is connected to actual hardware part via HdmiCecService. It provides with methods
+ * to send CEC messages to other device on the bus, and listener that allows to receive
+ * incoming messages to the device.
+ *
+ * @hide
+ */
+public final class HdmiCecClient {
+    private static final String TAG = "HdmiCecClient";
+
+    private final IHdmiCecService mService;
+    private final IBinder mBinder;
+
+    /**
+     * Listener used by the client to get the incoming messages.
+     */
+    public static abstract class Listener {
+        /**
+         * Called when CEC message arrives. Override this method to receive the incoming
+         * CEC messages from other device on the bus.
+         *
+         * @param message {@link HdmiCecMessage} object
+         */
+        public void onMessageReceived(HdmiCecMessage message) { }
+
+        /**
+         * Called when hotplug event occurs. Override this method to receive the events.
+         *
+         * @param connected true if the cable is connected; otherwise false.
+         */
+        public void onCableStatusChanged(boolean connected) { }
+    }
+
+    // Private constructor.
+    private HdmiCecClient(IHdmiCecService service, IBinder b) {
+        mService = service;
+        mBinder = b;
+    }
+
+    // Factory method for HdmiCecClient.
+    // Declared package-private. Accessed by HdmiCecManager only.
+    static HdmiCecClient create(IHdmiCecService service, IBinder b) {
+        return new HdmiCecClient(service, b);
+    }
+
+    /**
+     * Send &lt;Active Source&gt; message.
+     */
+    public void sendActiveSource() {
+        try {
+            mService.sendActiveSource(mBinder);
+        } catch (RemoteException e) {
+            Log.e(TAG, "sendActiveSource threw exception ", e);
+        }
+    }
+
+    /**
+     * Send &lt;Inactive Source&gt; message.
+     */
+    public void sendInactiveSource() {
+        try {
+            mService.sendInactiveSource(mBinder);
+        } catch (RemoteException e) {
+            Log.e(TAG, "sendInactiveSource threw exception ", e);
+        }
+    }
+
+    /**
+     * Send &lt;Text View On&gt; message.
+     */
+    public void sendTextViewOn() {
+        try {
+            mService.sendTextViewOn(mBinder);
+        } catch (RemoteException e) {
+            Log.e(TAG, "sendTextViewOn threw exception ", e);
+        }
+    }
+
+    /**
+     * Send &lt;Image View On&gt; message.
+     */
+    public void sendImageViewOn() {
+        try {
+            mService.sendImageViewOn(mBinder);
+        } catch (RemoteException e) {
+            Log.e(TAG, "sendImageViewOn threw exception ", e);
+        }
+    }
+
+    /**
+     * Send &lt;Give Device Power Status&gt; message.
+     *
+     * @param address logical address of the device to send the message to, such as
+     *        {@link HdmiCec#ADDR_TV}.
+     */
+    public void sendGiveDevicePowerStatus(int address) {
+        try {
+            mService.sendGiveDevicePowerStatus(mBinder, address);
+        } catch (RemoteException e) {
+            Log.e(TAG, "sendGiveDevicePowerStatus threw exception ", e);
+        }
+    }
+
+    /**
+     * Returns true if the TV or attached display is powered on.
+     * <p>
+     * The result of this method is only meaningful on playback devices (where the device
+     * type is {@link HdmiCec#DEVICE_PLAYBACK}).
+     * </p>
+     *
+     * @return true if TV is on; otherwise false.
+     */
+    public boolean isTvOn() {
+        try {
+            return mService.isTvOn(mBinder);
+        } catch (RemoteException e) {
+            Log.e(TAG, "isTvOn threw exception ", e);
+        }
+        return false;
+    }
+}
diff --git a/core/java/android/hardware/hdmi/HdmiCecManager.java b/core/java/android/hardware/hdmi/HdmiCecManager.java
new file mode 100644
index 0000000..d18c7a9
--- /dev/null
+++ b/core/java/android/hardware/hdmi/HdmiCecManager.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.hdmi;
+
+import android.os.IBinder;
+import android.os.RemoteException;
+
+/**
+ * The HdmiCecManager class is used to provide an HdmiCecClient instance,
+ * get various information on HDMI ports configuration. It is connected to actual hardware
+ * via HdmiCecService.
+ *
+ * @hide
+ */
+public final class HdmiCecManager {
+    private final IHdmiCecService mService;
+
+    /**
+     * @hide - hide this constructor because it has a parameter of type IHdmiCecService,
+     * which is a system private class. The right way to create an instance of this class
+     * is using the factory Context.getSystemService.
+     */
+    public HdmiCecManager(IHdmiCecService service) {
+        mService = service;
+    }
+
+    /**
+     * Provide the HdmiCecClient instance of the given type. It also registers the listener
+     * for client to get the events coming to the device.
+     *
+     * @param type type of the HDMI-CEC logical device
+     * @param listener listener to be called
+     * @return {@link HdmiCecClient} instance. {@code null} on failure.
+     */
+    public HdmiCecClient getClient(int type, HdmiCecClient.Listener listener) {
+        if (mService == null) {
+            return null;
+        }
+        try {
+            IBinder b = mService.allocateLogicalDevice(type, getListenerWrapper(listener));
+            return HdmiCecClient.create(mService, b);
+        } catch (RemoteException e) {
+            return null;
+        }
+    }
+
+    private IHdmiCecListener getListenerWrapper(final HdmiCecClient.Listener listener) {
+        // TODO: The message/events are not yet forwarded to client since it is not clearly
+        //       defined as to how/who to handle them. Revisit it once the decision is
+        //       made on what messages will have to reach the clients, what will be
+        //       handled by service/manager.
+        return new IHdmiCecListener.Stub() {
+            @Override
+            public void onMessageReceived(HdmiCecMessage message) {
+                // Do nothing.
+            }
+
+            @Override
+            public void onCableStatusChanged(boolean connected) {
+                // Do nothing.
+            }
+        };
+    }
+}
diff --git a/services/java/com/android/server/power/DisplayBlanker.java b/core/java/android/hardware/hdmi/HdmiCecMessage.aidl
similarity index 70%
copy from services/java/com/android/server/power/DisplayBlanker.java
copy to core/java/android/hardware/hdmi/HdmiCecMessage.aidl
index 6072053..6687ba4 100644
--- a/services/java/com/android/server/power/DisplayBlanker.java
+++ b/core/java/android/hardware/hdmi/HdmiCecMessage.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 The Android Open Source Project
+ * Copyright (C) 2014 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,12 +14,6 @@
  * limitations under the License.
  */
 
-package com.android.server.power;
+package android.hardware.hdmi;
 
-/**
- * Blanks or unblanks all displays.
- */
-interface DisplayBlanker {
-    public void blankAllDisplays();
-    public void unblankAllDisplays();
-}
+parcelable HdmiCecMessage;
diff --git a/core/java/android/hardware/hdmi/HdmiCecMessage.java b/core/java/android/hardware/hdmi/HdmiCecMessage.java
new file mode 100644
index 0000000..63add2e
--- /dev/null
+++ b/core/java/android/hardware/hdmi/HdmiCecMessage.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.hdmi;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Arrays;
+
+/**
+ * A class to encapsulate HDMI-CEC message used for the devices connected via
+ * HDMI cable to communicate with one another. A message is defined by its
+ * source and destination address, command (or opcode), and optional parameters.
+ *
+ * @hide
+ */
+public final class HdmiCecMessage implements Parcelable {
+
+    private static final int MAX_MESSAGE_LENGTH = 16;
+
+    private final int mSource;
+    private final int mDestination;
+
+    private final int mOpcode;
+    private final byte[] mParams;
+
+    /**
+     * Constructor.
+     */
+    public HdmiCecMessage(int source, int destination, int opcode, byte[] params) {
+        mSource = source;
+        mDestination = destination;
+        mOpcode = opcode;
+        mParams = Arrays.copyOf(params, params.length);
+    }
+
+    /**
+     * Return the source address field of the message. It is the logical address
+     * of the device which generated the message.
+     *
+     * @return source address
+     */
+    public int getSource() {
+        return mSource;
+    }
+
+    /**
+     * Return the destination address field of the message. It is the logical address
+     * of the device to which the message is sent.
+     *
+     * @return destination address
+     */
+    public int getDestination() {
+        return mDestination;
+    }
+
+    /**
+     * Return the opcode field of the message. It is the type of the message that
+     * tells the destination device what to do.
+     *
+     * @return opcode
+     */
+    public int getOpcode() {
+        return mOpcode;
+    }
+
+    /**
+     * Return the parameter field of the message. The contents of parameter varies
+     * from opcode to opcode, and is used together with opcode to describe
+     * the action for the destination device to take.
+     *
+     * @return parameter
+     */
+    public byte[] getParams() {
+        return mParams;
+    }
+
+    /**
+     * Describe the kinds of special objects contained in this Parcelable's
+     * marshalled representation.
+     */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /**
+     * Flatten this object in to a Parcel.
+     *
+     * @param dest The Parcel in which the object should be written.
+     * @param flags Additional flags about how the object should be written.
+     *        May be 0 or {@link Parcelable#PARCELABLE_WRITE_RETURN_VALUE}.
+     */
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mSource);
+        dest.writeInt(mDestination);
+        dest.writeInt(mOpcode);
+        dest.writeInt(mParams.length);
+        dest.writeByteArray(mParams);
+    }
+
+    public static final Parcelable.Creator<HdmiCecMessage> CREATOR
+            = new Parcelable.Creator<HdmiCecMessage>() {
+        /**
+         * Rebuild a HdmiCecMessage previously stored with writeToParcel().
+         * @param p HdmiCecMessage object to read the Rating from
+         * @return a new HdmiCecMessage created from the data in the parcel
+         */
+        public HdmiCecMessage createFromParcel(Parcel p) {
+            int source = p.readInt();
+            int destination = p.readInt();
+            int opcode = p.readInt();
+            byte[] params = new byte[p.readInt()];
+            p.readByteArray(params);
+            return new HdmiCecMessage(source, destination, opcode, params);
+        }
+        public HdmiCecMessage[] newArray(int size) {
+            return new HdmiCecMessage[size];
+        }
+    };
+
+    @Override
+    public String toString() {
+        StringBuffer s = new StringBuffer();
+        s.append(String.format("src: %d dst: %d op: %2X params: ", mSource, mDestination, mOpcode));
+        for (byte data : mParams) {
+            s.append(String.format("%02X ", data));
+        }
+        return s.toString();
+    }
+}
+
diff --git a/services/java/com/android/server/power/DisplayBlanker.java b/core/java/android/hardware/hdmi/IHdmiCecListener.aidl
similarity index 60%
copy from services/java/com/android/server/power/DisplayBlanker.java
copy to core/java/android/hardware/hdmi/IHdmiCecListener.aidl
index 6072053..d281ce6 100644
--- a/services/java/com/android/server/power/DisplayBlanker.java
+++ b/core/java/android/hardware/hdmi/IHdmiCecListener.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 The Android Open Source Project
+ * Copyright (C) 2014 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,12 +14,16 @@
  * limitations under the License.
  */
 
-package com.android.server.power;
+package android.hardware.hdmi;
+
+import android.hardware.hdmi.HdmiCecMessage;
 
 /**
- * Blanks or unblanks all displays.
+ * Interface definition for HdmiCecService to do interprocess communcation.
+ *
+ * @hide
  */
-interface DisplayBlanker {
-    public void blankAllDisplays();
-    public void unblankAllDisplays();
+oneway interface IHdmiCecListener {
+    void onMessageReceived(in HdmiCecMessage message);
+    void onCableStatusChanged(in boolean connected);
 }
diff --git a/core/java/android/hardware/hdmi/IHdmiCecService.aidl b/core/java/android/hardware/hdmi/IHdmiCecService.aidl
new file mode 100644
index 0000000..ecdd345
--- /dev/null
+++ b/core/java/android/hardware/hdmi/IHdmiCecService.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.hdmi;
+
+import android.hardware.hdmi.HdmiCecMessage;
+import android.hardware.hdmi.IHdmiCecListener;
+import android.os.IBinder;
+
+/**
+ * Binder interface that components running in the appplication process
+ * will use to enable HDMI-CEC protocol exchange with other devices.
+ *
+ * @hide
+ */
+interface IHdmiCecService {
+    IBinder allocateLogicalDevice(int type, IHdmiCecListener listener);
+    void removeServiceListener(IBinder b, IHdmiCecListener listener);
+    void sendActiveSource(IBinder b);
+    void sendInactiveSource(IBinder b);
+    void sendImageViewOn(IBinder b);
+    void sendTextViewOn(IBinder b);
+    void sendGiveDevicePowerStatus(IBinder b, int address);
+    boolean isTvOn(IBinder b);
+    void sendMessage(IBinder b, in HdmiCecMessage message);
+}
+
diff --git a/core/java/android/hardware/input/IInputManager.aidl b/core/java/android/hardware/input/IInputManager.aidl
index 9b6f82a..f1e7e98 100644
--- a/core/java/android/hardware/input/IInputManager.aidl
+++ b/core/java/android/hardware/input/IInputManager.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.input;
 
+import android.hardware.input.InputDeviceIdentifier;
 import android.hardware.input.KeyboardLayout;
 import android.hardware.input.IInputDevicesChangedListener;
 import android.os.IBinder;
@@ -41,13 +42,13 @@
     // Keyboard layouts configuration.
     KeyboardLayout[] getKeyboardLayouts();
     KeyboardLayout getKeyboardLayout(String keyboardLayoutDescriptor);
-    String getCurrentKeyboardLayoutForInputDevice(String inputDeviceDescriptor);
-    void setCurrentKeyboardLayoutForInputDevice(String inputDeviceDescriptor,
+    String getCurrentKeyboardLayoutForInputDevice(in InputDeviceIdentifier identifier);
+    void setCurrentKeyboardLayoutForInputDevice(in InputDeviceIdentifier identifier,
             String keyboardLayoutDescriptor);
-    String[] getKeyboardLayoutsForInputDevice(String inputDeviceDescriptor);
-    void addKeyboardLayoutForInputDevice(String inputDeviceDescriptor,
+    String[] getKeyboardLayoutsForInputDevice(in InputDeviceIdentifier identifier);
+    void addKeyboardLayoutForInputDevice(in InputDeviceIdentifier identifier,
             String keyboardLayoutDescriptor);
-    void removeKeyboardLayoutForInputDevice(String inputDeviceDescriptor,
+    void removeKeyboardLayoutForInputDevice(in InputDeviceIdentifier identifier,
             String keyboardLayoutDescriptor);
 
     // Registers an input devices changed listener.
diff --git a/services/java/com/android/server/power/DisplayBlanker.java b/core/java/android/hardware/input/InputDeviceIdentifier.aidl
similarity index 70%
copy from services/java/com/android/server/power/DisplayBlanker.java
copy to core/java/android/hardware/input/InputDeviceIdentifier.aidl
index 6072053..7234a91 100644
--- a/services/java/com/android/server/power/DisplayBlanker.java
+++ b/core/java/android/hardware/input/InputDeviceIdentifier.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 The Android Open Source Project
+ * 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.
@@ -14,12 +14,6 @@
  * limitations under the License.
  */
 
-package com.android.server.power;
+package android.hardware.input;
 
-/**
- * Blanks or unblanks all displays.
- */
-interface DisplayBlanker {
-    public void blankAllDisplays();
-    public void unblankAllDisplays();
-}
+parcelable InputDeviceIdentifier;
diff --git a/core/java/android/hardware/input/InputDeviceIdentifier.java b/core/java/android/hardware/input/InputDeviceIdentifier.java
new file mode 100644
index 0000000..5e832e3
--- /dev/null
+++ b/core/java/android/hardware/input/InputDeviceIdentifier.java
@@ -0,0 +1,82 @@
+/*
+ * 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.hardware.input;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Wrapper for passing identifying information for input devices.
+ *
+ * @hide
+ */
+public final class InputDeviceIdentifier implements Parcelable {
+    private final String mDescriptor;
+    private final int mVendorId;
+    private final int mProductId;
+
+    public InputDeviceIdentifier(String descriptor, int vendorId, int productId) {
+        this.mDescriptor = descriptor;
+        this.mVendorId = vendorId;
+        this.mProductId = productId;
+    }
+
+    private InputDeviceIdentifier(Parcel src) {
+        mDescriptor = src.readString();
+        mVendorId = src.readInt();
+        mProductId = src.readInt();
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(mDescriptor);
+        dest.writeInt(mVendorId);
+        dest.writeInt(mProductId);
+    }
+
+    public String getDescriptor() {
+        return mDescriptor;
+    }
+
+    public int getVendorId() {
+        return mVendorId;
+    }
+
+    public int getProductId() {
+        return mProductId;
+    }
+
+    public static final Parcelable.Creator<InputDeviceIdentifier> CREATOR =
+            new Parcelable.Creator<InputDeviceIdentifier>() {
+
+        @Override
+        public InputDeviceIdentifier createFromParcel(Parcel source) {
+            return new InputDeviceIdentifier(source);
+        }
+
+        @Override
+        public InputDeviceIdentifier[] newArray(int size) {
+            return new InputDeviceIdentifier[size];
+        }
+
+    };
+}
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index 30e69a6..a2aeafb 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -26,6 +26,8 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
+import android.os.Parcel;
+import android.os.Parcelable;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.Vibrator;
@@ -373,20 +375,17 @@
     }
 
     /**
-     * Gets the current keyboard layout descriptor for the specified input device.
+     * Gets the current keyboard layout descriptor for the specified input
+     * device.
      *
-     * @param inputDeviceDescriptor The input device descriptor.
-     * @return The keyboard layout descriptor, or null if no keyboard layout has been set.
-     *
+     * @param identifier Identifier for the input device
+     * @return The keyboard layout descriptor, or null if no keyboard layout has
+     *         been set.
      * @hide
      */
-    public String getCurrentKeyboardLayoutForInputDevice(String inputDeviceDescriptor) {
-        if (inputDeviceDescriptor == null) {
-            throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
-        }
-
+    public String getCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier) {
         try {
-            return mIm.getCurrentKeyboardLayoutForInputDevice(inputDeviceDescriptor);
+            return mIm.getCurrentKeyboardLayoutForInputDevice(identifier);
         } catch (RemoteException ex) {
             Log.w(TAG, "Could not get current keyboard layout for input device.", ex);
             return null;
@@ -394,28 +393,29 @@
     }
 
     /**
-     * Sets the current keyboard layout descriptor for the specified input device.
+     * Sets the current keyboard layout descriptor for the specified input
+     * device.
      * <p>
-     * This method may have the side-effect of causing the input device in question
-     * to be reconfigured.
+     * This method may have the side-effect of causing the input device in
+     * question to be reconfigured.
      * </p>
      *
-     * @param inputDeviceDescriptor The input device descriptor.
-     * @param keyboardLayoutDescriptor The keyboard layout descriptor to use, must not be null.
-     *
+     * @param identifier The identifier for the input device.
+     * @param keyboardLayoutDescriptor The keyboard layout descriptor to use,
+     *            must not be null.
      * @hide
      */
-    public void setCurrentKeyboardLayoutForInputDevice(String inputDeviceDescriptor,
+    public void setCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
             String keyboardLayoutDescriptor) {
-        if (inputDeviceDescriptor == null) {
-            throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
+        if (identifier == null) {
+            throw new IllegalArgumentException("identifier must not be null");
         }
         if (keyboardLayoutDescriptor == null) {
             throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
         }
 
         try {
-            mIm.setCurrentKeyboardLayoutForInputDevice(inputDeviceDescriptor,
+            mIm.setCurrentKeyboardLayoutForInputDevice(identifier,
                     keyboardLayoutDescriptor);
         } catch (RemoteException ex) {
             Log.w(TAG, "Could not set current keyboard layout for input device.", ex);
@@ -423,20 +423,20 @@
     }
 
     /**
-     * Gets all keyboard layout descriptors that are enabled for the specified input device.
+     * Gets all keyboard layout descriptors that are enabled for the specified
+     * input device.
      *
-     * @param inputDeviceDescriptor The input device descriptor.
+     * @param identifier The identifier for the input device.
      * @return The keyboard layout descriptors.
-     *
      * @hide
      */
-    public String[] getKeyboardLayoutsForInputDevice(String inputDeviceDescriptor) {
-        if (inputDeviceDescriptor == null) {
+    public String[] getKeyboardLayoutsForInputDevice(InputDeviceIdentifier identifier) {
+        if (identifier == null) {
             throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
         }
 
         try {
-            return mIm.getKeyboardLayoutsForInputDevice(inputDeviceDescriptor);
+            return mIm.getKeyboardLayoutsForInputDevice(identifier);
         } catch (RemoteException ex) {
             Log.w(TAG, "Could not get keyboard layouts for input device.", ex);
             return ArrayUtils.emptyArray(String.class);
@@ -446,18 +446,18 @@
     /**
      * Adds the keyboard layout descriptor for the specified input device.
      * <p>
-     * This method may have the side-effect of causing the input device in question
-     * to be reconfigured.
+     * This method may have the side-effect of causing the input device in
+     * question to be reconfigured.
      * </p>
      *
-     * @param inputDeviceDescriptor The input device descriptor.
-     * @param keyboardLayoutDescriptor The descriptor of the keyboard layout to add.
-     *
+     * @param identifier The identifier for the input device.
+     * @param keyboardLayoutDescriptor The descriptor of the keyboard layout to
+     *            add.
      * @hide
      */
-    public void addKeyboardLayoutForInputDevice(String inputDeviceDescriptor,
+    public void addKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
             String keyboardLayoutDescriptor) {
-        if (inputDeviceDescriptor == null) {
+        if (identifier == null) {
             throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
         }
         if (keyboardLayoutDescriptor == null) {
@@ -465,7 +465,7 @@
         }
 
         try {
-            mIm.addKeyboardLayoutForInputDevice(inputDeviceDescriptor, keyboardLayoutDescriptor);
+            mIm.addKeyboardLayoutForInputDevice(identifier, keyboardLayoutDescriptor);
         } catch (RemoteException ex) {
             Log.w(TAG, "Could not add keyboard layout for input device.", ex);
         }
@@ -474,18 +474,18 @@
     /**
      * Removes the keyboard layout descriptor for the specified input device.
      * <p>
-     * This method may have the side-effect of causing the input device in question
-     * to be reconfigured.
+     * This method may have the side-effect of causing the input device in
+     * question to be reconfigured.
      * </p>
      *
-     * @param inputDeviceDescriptor The input device descriptor.
-     * @param keyboardLayoutDescriptor The descriptor of the keyboard layout to remove.
-     *
+     * @param identifier The identifier for the input device.
+     * @param keyboardLayoutDescriptor The descriptor of the keyboard layout to
+     *            remove.
      * @hide
      */
-    public void removeKeyboardLayoutForInputDevice(String inputDeviceDescriptor,
+    public void removeKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
             String keyboardLayoutDescriptor) {
-        if (inputDeviceDescriptor == null) {
+        if (identifier == null) {
             throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
         }
         if (keyboardLayoutDescriptor == null) {
@@ -493,7 +493,7 @@
         }
 
         try {
-            mIm.removeKeyboardLayoutForInputDevice(inputDeviceDescriptor, keyboardLayoutDescriptor);
+            mIm.removeKeyboardLayoutForInputDevice(identifier, keyboardLayoutDescriptor);
         } catch (RemoteException ex) {
             Log.w(TAG, "Could not remove keyboard layout for input device.", ex);
         }
diff --git a/core/java/android/hardware/input/InputManagerInternal.java b/core/java/android/hardware/input/InputManagerInternal.java
new file mode 100644
index 0000000..6a392dd
--- /dev/null
+++ b/core/java/android/hardware/input/InputManagerInternal.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.input;
+
+import android.hardware.display.DisplayViewport;
+import android.view.InputEvent;
+
+/**
+ * Input manager local system service interface.
+ *
+ * @hide Only for use within the system server.
+ */
+public abstract class InputManagerInternal {
+    public abstract boolean injectInputEvent(InputEvent event, int displayId, int mode);
+
+    /**
+     * Called by the display manager to set information about the displays as needed
+     * by the input system.  The input system must copy this information to retain it.
+     */
+    public abstract void setDisplayViewports(DisplayViewport defaultViewport,
+            DisplayViewport externalTouchViewport);
+
+    /**
+     * Called by the power manager to tell the input manager whether it should start
+     * watching for wake events.
+     */
+    public abstract void setInteractive(boolean interactive);
+}
diff --git a/core/java/android/hardware/usb/UsbDevice.java b/core/java/android/hardware/usb/UsbDevice.java
index d1e63f6..320ccfe 100644
--- a/core/java/android/hardware/usb/UsbDevice.java
+++ b/core/java/android/hardware/usb/UsbDevice.java
@@ -91,6 +91,7 @@
      * Returns the manufacturer name of the device.
      *
      * @return the manufacturer name
+     * @hide
      */
     public String getManufacturerName() {
         return mManufacturerName;
@@ -100,6 +101,7 @@
      * Returns the product name of the device.
      *
      * @return the product name
+     * @hide
      */
     public String getProductName() {
         return mProductName;
@@ -109,6 +111,7 @@
      * Returns the serial number of the device.
      *
      * @return the serial number name
+     * @hide
      */
     public String getSerialNumber() {
         return mSerialNumber;
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 70c8750..4eecfa9 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -361,11 +361,17 @@
      */
     public static final int TYPE_MOBILE_IA = 14;
 
-    /** {@hide} */
-    public static final int MAX_RADIO_TYPE   = TYPE_MOBILE_IA;
+    /**
+     * The network that uses proxy to achieve connectivity.
+     * {@hide}
+     */
+    public static final int TYPE_PROXY = 16;
 
     /** {@hide} */
-    public static final int MAX_NETWORK_TYPE = TYPE_MOBILE_IA;
+    public static final int MAX_RADIO_TYPE   = TYPE_PROXY;
+
+    /** {@hide} */
+    public static final int MAX_NETWORK_TYPE = TYPE_PROXY;
 
     /**
      * If you want to set the default network preference,you can directly
@@ -446,6 +452,8 @@
                 return "WIFI_P2P";
             case TYPE_MOBILE_IA:
                 return "MOBILE_IA";
+            case TYPE_PROXY:
+                return "PROXY";
             default:
                 return Integer.toString(type);
         }
diff --git a/core/java/android/net/ProxyDataTracker.java b/core/java/android/net/ProxyDataTracker.java
new file mode 100644
index 0000000..461e8b8
--- /dev/null
+++ b/core/java/android/net/ProxyDataTracker.java
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.ServiceConnection;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.Log;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * A data tracker responsible for bringing up and tearing down the system proxy server.
+ *
+ * {@hide}
+ */
+public class ProxyDataTracker extends BaseNetworkStateTracker {
+    private static final String TAG = "ProxyDataTracker";
+    private static final String NETWORK_TYPE = "PROXY";
+
+    // TODO: investigate how to get these DNS addresses from the system.
+    private static final String DNS1 = "8.8.8.8";
+    private static final String DNS2 = "8.8.4.4";
+    private static final String REASON_ENABLED = "enabled";
+    private static final String REASON_DISABLED = "disabled";
+    private static final String REASON_PROXY_DOWN = "proxy_down";
+
+    private static final int MSG_TEAR_DOWN_REQUEST = 1;
+    private static final int MSG_SETUP_REQUEST = 2;
+
+    private static final String PERMISSION_PROXY_STATUS_SENDER =
+            "android.permission.ACCESS_NETWORK_CONDITIONS";
+    private static final String ACTION_PROXY_STATUS_CHANGE =
+            "com.android.net.PROXY_STATUS_CHANGE";
+    private static final String KEY_IS_PROXY_AVAILABLE = "is_proxy_available";
+    private static final String KEY_REPLY_TO_MESSENGER_BINDER = "reply_to_messenger_binder";
+    private static final String KEY_REPLY_TO_MESSENGER_BINDER_BUNDLE =
+            "reply_to_messenger_binder_bundle";
+
+    private Handler mTarget;
+    private Messenger mProxyStatusService;
+    private AtomicBoolean mReconnectRequested = new AtomicBoolean(false);
+    private AtomicBoolean mIsProxyAvailable = new AtomicBoolean(false);
+    private final AtomicInteger mDefaultGatewayAddr = new AtomicInteger(0);
+
+    private final BroadcastReceiver mProxyStatusServiceListener = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (intent.getAction().equals(ACTION_PROXY_STATUS_CHANGE)) {
+                mIsProxyAvailable.set(intent.getBooleanExtra(KEY_IS_PROXY_AVAILABLE, false));
+                if (mIsProxyAvailable.get()) {
+                    Bundle bundle = intent.getBundleExtra(KEY_REPLY_TO_MESSENGER_BINDER_BUNDLE);
+                    if (bundle == null || bundle.getBinder(KEY_REPLY_TO_MESSENGER_BINDER) == null) {
+                        Log.e(TAG, "no messenger binder in the intent to send future requests");
+                        mIsProxyAvailable.set(false);
+                        return;
+                    }
+                    mProxyStatusService =
+                            new Messenger(bundle.getBinder(KEY_REPLY_TO_MESSENGER_BINDER));
+                    // If there is a pending reconnect request, do it now.
+                    if (mReconnectRequested.get()) {
+                        reconnect();
+                    }
+                } else {
+                    setDetailedState(NetworkInfo.DetailedState.DISCONNECTED,
+                            REASON_PROXY_DOWN, null);
+                }
+            } else {
+                Log.d(TAG, "Unrecognized broadcast intent");
+            }
+        }
+    };
+
+    /**
+     * Create a new ProxyDataTracker
+     */
+    public ProxyDataTracker() {
+        mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_PROXY, 0, NETWORK_TYPE, "");
+        mLinkProperties = new LinkProperties();
+        mLinkCapabilities = new LinkCapabilities();
+        mNetworkInfo.setIsAvailable(true);
+        try {
+          mLinkProperties.addDns(InetAddress.getByName(DNS1));
+          mLinkProperties.addDns(InetAddress.getByName(DNS2));
+        } catch (UnknownHostException e) {
+          Log.e(TAG, "Could not add DNS address", e);
+        }
+    }
+
+    public Object Clone() throws CloneNotSupportedException {
+        throw new CloneNotSupportedException();
+    }
+
+    @Override
+    public void startMonitoring(Context context, Handler target) {
+        mContext = context;
+        mTarget = target;
+        mContext.registerReceiver(mProxyStatusServiceListener,
+                new IntentFilter(ACTION_PROXY_STATUS_CHANGE),
+                PERMISSION_PROXY_STATUS_SENDER,
+                null);
+    }
+
+    /**
+     * Disable connectivity to the network.
+     */
+    public boolean teardown() {
+        setTeardownRequested(true);
+        mReconnectRequested.set(false);
+        try {
+            if (mIsProxyAvailable.get() && mProxyStatusService != null) {
+                mProxyStatusService.send(Message.obtain(null, MSG_TEAR_DOWN_REQUEST));
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "Unable to connect to proxy status service", e);
+            return false;
+        }
+        setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, REASON_DISABLED, null);
+        return true;
+    }
+
+    /**
+     * Re-enable proxy data connectivity after a {@link #teardown()}.
+     */
+    public boolean reconnect() {
+        mReconnectRequested.set(true);
+        setTeardownRequested(false);
+        if (!mIsProxyAvailable.get()) {
+            Log.w(TAG, "Reconnect requested even though proxy service is not up. Bailing.");
+            return false;
+        }
+        setDetailedState(NetworkInfo.DetailedState.CONNECTING, REASON_ENABLED, null);
+
+        try {
+            mProxyStatusService.send(Message.obtain(null, MSG_SETUP_REQUEST));
+        } catch (RemoteException e) {
+            Log.e(TAG, "Unable to connect to proxy status service", e);
+            setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, REASON_PROXY_DOWN, null);
+            return false;
+        }
+        // We'll assume proxy is set up successfully. If not, a status change broadcast will be
+        // received afterwards to indicate any failure.
+        setDetailedState(NetworkInfo.DetailedState.CONNECTED, REASON_ENABLED, null);
+        return true;
+    }
+
+    /**
+     * Fetch default gateway address for the network
+     */
+    public int getDefaultGatewayAddr() {
+        return mDefaultGatewayAddr.get();
+    }
+
+    /**
+     * Return the system properties name associated with the tcp buffer sizes
+     * for this network.
+     */
+    public String getTcpBufferSizesPropName() {
+        return "net.tcp.buffersize.wifi";
+    }
+
+    /**
+     * Record the detailed state of a network, and if it is a
+     * change from the previous state, send a notification to
+     * any listeners.
+     * @param state the new @{code DetailedState}
+     * @param reason a {@code String} indicating a reason for the state change,
+     * if one was supplied. May be {@code null}.
+     * @param extraInfo optional {@code String} providing extra information about the state change
+     */
+    private void setDetailedState(NetworkInfo.DetailedState state, String reason,
+            String extraInfo) {
+        mNetworkInfo.setDetailedState(state, reason, extraInfo);
+        Message msg = mTarget.obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo);
+        msg.sendToTarget();
+    }
+}
diff --git a/core/java/android/net/nsd/NsdServiceInfo.java b/core/java/android/net/nsd/NsdServiceInfo.java
index 205a21d..8f52a7c 100644
--- a/core/java/android/net/nsd/NsdServiceInfo.java
+++ b/core/java/android/net/nsd/NsdServiceInfo.java
@@ -18,8 +18,15 @@
 
 import android.os.Parcelable;
 import android.os.Parcel;
+import android.util.Log;
+import android.util.ArrayMap;
 
+import java.io.UnsupportedEncodingException;
 import java.net.InetAddress;
+import java.nio.charset.StandardCharsets;
+import java.util.Collections;
+import java.util.Map;
+
 
 /**
  * A class representing service information for network service discovery
@@ -27,11 +34,13 @@
  */
 public final class NsdServiceInfo implements Parcelable {
 
+    private static final String TAG = "NsdServiceInfo";
+
     private String mServiceName;
 
     private String mServiceType;
 
-    private DnsSdTxtRecord mTxtRecord;
+    private final ArrayMap<String, byte[]> mTxtRecord = new ArrayMap<String, byte[]>();
 
     private InetAddress mHost;
 
@@ -41,10 +50,9 @@
     }
 
     /** @hide */
-    public NsdServiceInfo(String sn, String rt, DnsSdTxtRecord tr) {
+    public NsdServiceInfo(String sn, String rt) {
         mServiceName = sn;
         mServiceType = rt;
-        mTxtRecord = tr;
     }
 
     /** Get the service name */
@@ -67,16 +75,6 @@
         mServiceType = s;
     }
 
-    /** @hide */
-    public DnsSdTxtRecord getTxtRecord() {
-        return mTxtRecord;
-    }
-
-    /** @hide */
-    public void setTxtRecord(DnsSdTxtRecord t) {
-        mTxtRecord = new DnsSdTxtRecord(t);
-    }
-
     /** Get the host address. The host address is valid for a resolved service. */
     public InetAddress getHost() {
         return mHost;
@@ -97,14 +95,139 @@
         mPort = p;
     }
 
+    /** @hide */
+    public void setAttribute(String key, byte[] value) {
+        // Key must be printable US-ASCII, excluding =.
+        for (int i = 0; i < key.length(); ++i) {
+            char character = key.charAt(i);
+            if (character < 0x20 || character > 0x7E) {
+                throw new IllegalArgumentException("Key strings must be printable US-ASCII");
+            } else if (character == 0x3D) {
+                throw new IllegalArgumentException("Key strings must not include '='");
+            }
+        }
+
+        // Key length + value length must be < 255.
+        if (key.length() + (value == null ? 0 : value.length) >= 255) {
+            throw new IllegalArgumentException("Key length + value length must be < 255 bytes");
+        }
+
+        // Warn if key is > 9 characters, as recommended by RFC 6763 section 6.4.
+        if (key.length() > 9) {
+            Log.w(TAG, "Key lengths > 9 are discouraged: " + key);
+        }
+
+        // Check against total TXT record size limits.
+        // Arbitrary 400 / 1300 byte limits taken from RFC 6763 section 6.2.
+        int txtRecordSize = getTxtRecordSize();
+        int futureSize = txtRecordSize + key.length() + (value == null ? 0 : value.length) + 2;
+        if (futureSize > 1300) {
+            throw new IllegalArgumentException("Total length of attributes must be < 1300 bytes");
+        } else if (futureSize > 400) {
+            Log.w(TAG, "Total length of all attributes exceeds 400 bytes; truncation may occur");
+        }
+
+        mTxtRecord.put(key, value);
+    }
+
+    /**
+     * Add a service attribute as a key/value pair.
+     *
+     * <p> Service attributes are included as DNS-SD TXT record pairs.
+     *
+     * <p> The key must be US-ASCII printable characters, excluding the '=' character.  Values may
+     * be UTF-8 strings or null.  The total length of key + value must be less than 255 bytes.
+     *
+     * <p> Keys should be short, ideally no more than 9 characters, and unique per instance of
+     * {@link NsdServiceInfo}.  Calling {@link #setAttribute} twice with the same key will overwrite
+     * first value.
+     * @hide
+     */
+    public void setAttribute(String key, String value) {
+        try {
+            setAttribute(key, value == null ? (byte []) null : value.getBytes("UTF-8"));
+        } catch (UnsupportedEncodingException e) {
+            throw new IllegalArgumentException("Value must be UTF-8");
+        }
+    }
+
+    /**
+     * Remove an attribute by key
+     * @hide
+     */
+    public void removeAttribute(String key) {
+        mTxtRecord.remove(key);
+    }
+
+    /**
+     * Retrive attributes as a map of String keys to byte[] values.
+     *
+     * <p> The returned map is unmodifiable; changes must be made through {@link #setAttribute} and
+     * {@link #removeAttribute}.
+     * @hide
+     */
+    public Map<String, byte[]> getAttributes() {
+        return Collections.unmodifiableMap(mTxtRecord);
+    }
+
+    private int getTxtRecordSize() {
+        int txtRecordSize = 0;
+        for (Map.Entry<String, byte[]> entry : mTxtRecord.entrySet()) {
+            txtRecordSize += 2;  // One for the length byte, one for the = between key and value.
+            txtRecordSize += entry.getKey().length();
+            byte[] value = entry.getValue();
+            txtRecordSize += value == null ? 0 : value.length;
+        }
+        return txtRecordSize;
+    }
+
+    /** @hide */
+    public byte[] getTxtRecord() {
+        int txtRecordSize = getTxtRecordSize();
+        if (txtRecordSize == 0) {
+            return null;
+        }
+
+        byte[] txtRecord = new byte[txtRecordSize];
+        int ptr = 0;
+        for (Map.Entry<String, byte[]> entry : mTxtRecord.entrySet()) {
+            String key = entry.getKey();
+            byte[] value = entry.getValue();
+
+            // One byte to record the length of this key/value pair.
+            txtRecord[ptr++] = (byte) (key.length() + (value == null ? 0 : value.length) + 1);
+
+            // The key, in US-ASCII.
+            // Note: use the StandardCharsets const here because it doesn't raise exceptions and we
+            // already know the key is ASCII at this point.
+            System.arraycopy(key.getBytes(StandardCharsets.US_ASCII), 0, txtRecord, ptr,
+                    key.length());
+            ptr += key.length();
+
+            // US-ASCII '=' character.
+            txtRecord[ptr++] = (byte)'=';
+
+            // The value, as any raw bytes.
+            if (value != null) {
+                System.arraycopy(value, 0, txtRecord, ptr, value.length);
+                ptr += value.length;
+            }
+        }
+        return txtRecord;
+    }
+
     public String toString() {
         StringBuffer sb = new StringBuffer();
 
-        sb.append("name: ").append(mServiceName).
-            append("type: ").append(mServiceType).
-            append("host: ").append(mHost).
-            append("port: ").append(mPort).
-            append("txtRecord: ").append(mTxtRecord);
+        sb.append("name: ").append(mServiceName)
+                .append(", type: ").append(mServiceType)
+                .append(", host: ").append(mHost)
+                .append(", port: ").append(mPort);
+
+        byte[] txtRecord = getTxtRecord();
+        if (txtRecord != null) {
+            sb.append(", txtRecord: ").append(new String(txtRecord, StandardCharsets.UTF_8));
+        }
         return sb.toString();
     }
 
@@ -117,14 +240,27 @@
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeString(mServiceName);
         dest.writeString(mServiceType);
-        dest.writeParcelable(mTxtRecord, flags);
         if (mHost != null) {
-            dest.writeByte((byte)1);
+            dest.writeInt(1);
             dest.writeByteArray(mHost.getAddress());
         } else {
-            dest.writeByte((byte)0);
+            dest.writeInt(0);
         }
         dest.writeInt(mPort);
+
+        // TXT record key/value pairs.
+        dest.writeInt(mTxtRecord.size());
+        for (String key : mTxtRecord.keySet()) {
+            byte[] value = mTxtRecord.get(key);
+            if (value != null) {
+                dest.writeInt(1);
+                dest.writeInt(value.length);
+                dest.writeByteArray(value);
+            } else {
+                dest.writeInt(0);
+            }
+            dest.writeString(key);
+        }
     }
 
     /** Implement the Parcelable interface */
@@ -134,15 +270,26 @@
                 NsdServiceInfo info = new NsdServiceInfo();
                 info.mServiceName = in.readString();
                 info.mServiceType = in.readString();
-                info.mTxtRecord = in.readParcelable(null);
 
-                if (in.readByte() == 1) {
+                if (in.readInt() == 1) {
                     try {
                         info.mHost = InetAddress.getByAddress(in.createByteArray());
                     } catch (java.net.UnknownHostException e) {}
                 }
 
                 info.mPort = in.readInt();
+
+                // TXT record key/value pairs.
+                int recordCount = in.readInt();
+                for (int i = 0; i < recordCount; ++i) {
+                    byte[] valueArray = null;
+                    if (in.readInt() == 1) {
+                        int valueLength = in.readInt();
+                        valueArray = new byte[valueLength];
+                        in.readByteArray(valueArray);
+                    }
+                    info.mTxtRecord.put(in.readString(), valueArray);
+                }
                 return info;
             }
 
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index b1a9ea30..5736c7a 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -782,7 +782,9 @@
      * {@hide}
      */
     public abstract long getScreenOnTime(long batteryRealtime, int which);
-    
+
+    public abstract long getInteractiveTime(long batteryRealtime, int which);
+
     public static final int SCREEN_BRIGHTNESS_DARK = 0;
     public static final int SCREEN_BRIGHTNESS_DIM = 1;
     public static final int SCREEN_BRIGHTNESS_MEDIUM = 2;
@@ -804,8 +806,6 @@
     public abstract long getScreenBrightnessTime(int brightnessBin,
             long batteryRealtime, int which);
 
-    public abstract int getInputEventCount(int which);
-    
     /**
      * Returns the time in microseconds that the phone has been on while the device was
      * running on battery.
@@ -1303,7 +1303,7 @@
                 wifiRunningTime / 1000, bluetoothOnTime / 1000,
                 mobileRxTotal, mobileTxTotal, wifiRxTotal, wifiTxTotal,
                 fullWakeLockTimeTotal, partialWakeLockTimeTotal,
-                getInputEventCount(which));
+                0 /*legacy input event count*/);
         
         // Dump screen brightness stats
         Object[] args = new Object[NUM_SCREEN_BRIGHTNESS_BINS];
@@ -1564,16 +1564,22 @@
         pw.println(sb.toString());
         
         final long screenOnTime = getScreenOnTime(batteryRealtime, which);
+        final long interactiveTime = getInteractiveTime(batteryRealtime, which);
         final long phoneOnTime = getPhoneOnTime(batteryRealtime, which);
         final long wifiRunningTime = getGlobalWifiRunningTime(batteryRealtime, which);
         final long wifiOnTime = getWifiOnTime(batteryRealtime, which);
         final long bluetoothOnTime = getBluetoothOnTime(batteryRealtime, which);
         sb.setLength(0);
         sb.append(prefix);
+                sb.append("  Interactive: "); formatTimeMs(sb, interactiveTime / 1000);
+                sb.append("("); sb.append(formatRatioLocked(interactiveTime, whichBatteryRealtime));
+                sb.append(")");
+        pw.println(sb.toString());
+        sb.setLength(0);
+        sb.append(prefix);
                 sb.append("  Screen on: "); formatTimeMs(sb, screenOnTime / 1000);
                 sb.append("("); sb.append(formatRatioLocked(screenOnTime, whichBatteryRealtime));
-                sb.append("), Input events: "); sb.append(getInputEventCount(which));
-                sb.append(", Active phone call: "); formatTimeMs(sb, phoneOnTime / 1000);
+                sb.append("), Active phone call: "); formatTimeMs(sb, phoneOnTime / 1000);
                 sb.append("("); sb.append(formatRatioLocked(phoneOnTime, whichBatteryRealtime));
                 sb.append(")");
         pw.println(sb.toString());
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index a23ecd7..65f62ed 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -501,6 +501,18 @@
          * </ul>
          */
         public static final int KITKAT = 19;
+
+        /**
+         * Android 4.4W: KitKat for watches, snacks on the run.
+         *
+         * <p>Applications targeting this or a later release will get these
+         * new changes in behavior:</p>
+         * <ul>
+         * <li>{@link android.app.AlertDialog} might not have a default background if the theme does
+         * not specify one.</li>
+         * </ul>
+         */
+        public static final int KITKAT_WATCH = 20;
     }
     
     /** The type of build, like "user" or "eng". */
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index 2de1204..f08afb9 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -627,9 +627,8 @@
      * in relative terms (e.g. was run #1 faster than run #2).  The times
      * for native methods will not change, so don't try to use this to
      * compare the performance of interpreted and native implementations of the
-     * same method.  As an alternative, consider using sampling-based method
-     * tracing via {@link #startMethodTracingSampling(String, int, int)} or
-     * "native" tracing in the emulator via {@link #startNativeTracing()}.
+     * same method.  As an alternative, consider using "native" tracing in the emulator via
+     * {@link #startNativeTracing()}.
      * </p>
      *
      * @param traceName    Name for the trace log file to create.
@@ -657,6 +656,7 @@
      * If the trace file given does not end in ".trace", it will be appended for you.
      * @param bufferSize    The maximum amount of trace data we gather. If not given, it defaults to 8MB.
      * @param intervalUs    The amount of time between each sample in microseconds.
+     * @hide
      */
     public static void startMethodTracingSampling(String traceName,
         int bufferSize, int intervalUs) {
diff --git a/core/java/android/os/FactoryTest.java b/core/java/android/os/FactoryTest.java
index ec99697..7a252f9 100644
--- a/core/java/android/os/FactoryTest.java
+++ b/core/java/android/os/FactoryTest.java
@@ -25,6 +25,20 @@
  * {@hide}
  */
 public final class FactoryTest {
+    public static final int FACTORY_TEST_OFF = 0;
+    public static final int FACTORY_TEST_LOW_LEVEL = 1;
+    public static final int FACTORY_TEST_HIGH_LEVEL = 2;
+
+    /**
+     * Gets the current factory test mode.
+     *
+     * @return One of: {@link #FACTORY_TEST_OFF}, {@link #FACTORY_TEST_LOW_LEVEL},
+     * or {@link #FACTORY_TEST_HIGH_LEVEL}.
+     */
+    public static int getMode() {
+        return SystemProperties.getInt("ro.factorytest", FACTORY_TEST_OFF);
+    }
+
     /**
      * When true, long-press on power should immediately cause the device to
      * shut down, without prompting the user.
diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl
index 56176a4..92af1a5 100644
--- a/core/java/android/os/IPowerManager.aidl
+++ b/core/java/android/os/IPowerManager.aidl
@@ -37,8 +37,8 @@
     void wakeUp(long time);
     void goToSleep(long time, int reason);
     void nap(long time);
+    boolean isInteractive();
 
-    boolean isScreenOn();
     void reboot(boolean confirm, String reason, boolean wait);
     void shutdown(boolean confirm, boolean wait);
     void crash(String message);
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 5e0d489..646bfef 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -191,6 +191,18 @@
     public static final int PROXIMITY_SCREEN_OFF_WAKE_LOCK = 0x00000020;
 
     /**
+     * Wake lock level: Put the screen in a low power state and allow the CPU to suspend
+     * if no other wake locks are held.
+     * <p>
+     * This is used by the dream manager to implement doze mode.  It currently
+     * has no effect unless the power manager is in the dozing state.
+     * </p>
+     *
+     * {@hide}
+     */
+    public static final int DOZE_WAKE_LOCK = 0x00000040;
+
+    /**
      * Mask for the wake lock level component of a combined wake lock level and flags integer.
      *
      * @hide
@@ -418,6 +430,7 @@
             case SCREEN_BRIGHT_WAKE_LOCK:
             case FULL_WAKE_LOCK:
             case PROXIMITY_SCREEN_OFF_WAKE_LOCK:
+            case DOZE_WAKE_LOCK:
                 break;
             default:
                 throw new IllegalArgumentException("Must specify a valid wake lock level.");
@@ -569,21 +582,64 @@
     }
 
     /**
-      * Returns whether the screen is currently on.
+      * Returns true if the device is in an interactive state.
       * <p>
-      * Only indicates whether the screen is on.  The screen could be either bright or dim.
+      * For historical reasons, the name of this method refers to the power state of
+      * the screen but it actually describes the overall interactive state of
+      * the device.  This method has been replaced by {@link #isInteractive}.
       * </p><p>
-      * {@samplecode
-      * PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
-      * boolean isScreenOn = pm.isScreenOn();
-      * }
+      * The value returned by this method only indicates whether the device is
+      * in an interactive state which may have nothing to do with the screen being
+      * on or off.  To determine the actual state of the screen,
+      * use {@link android.view.Display#getState}.
       * </p>
       *
-      * @return whether the screen is on (bright or dim).
+      * @return True if the device is in an interactive state.
+      *
+      * @deprecated Use {@link #isInteractive} instead.
       */
+    @Deprecated
     public boolean isScreenOn() {
+        return isInteractive();
+    }
+
+    /**
+     * Returns true if the device is in an interactive state.
+     * <p>
+     * When this method returns true, the device is awake and ready to interact
+     * with the user (although this is not a guarantee that the user is actively
+     * interacting with the device just this moment).  The main screen is usually
+     * turned on while in this state.  Certain features, such as the proximity
+     * sensor, may temporarily turn off the screen while still leaving the device in an
+     * interactive state.  Note in particular that the device is still considered
+     * to be interactive while dreaming (since dreams can be interactive) but not
+     * when it is dozing or asleep.
+     * </p><p>
+     * When this method returns false, the device is dozing or asleep and must
+     * be awoken before it will become ready to interact with the user again.  The
+     * main screen is usually turned off while in this state.  Certain features,
+     * such as "ambient mode" may cause the main screen to remain on (albeit in a
+     * low power state) to display system-provided content while the device dozes.
+     * </p><p>
+     * The system will send a {@link android.content.Intent#ACTION_SCREEN_ON screen on}
+     * or {@link android.content.Intent#ACTION_SCREEN_OFF screen off} broadcast
+     * whenever the interactive state of the device changes.  For historical reasons,
+     * the names of these broadcasts refer to the power state of the screen
+     * but they are actually sent in response to changes in the overall interactive
+     * state of the device, as described by this method.
+     * </p><p>
+     * Services may use the non-interactive state as a hint to conserve power
+     * since the user is not present.
+     * </p>
+     *
+     * @return True if the device is in an interactive state.
+     *
+     * @see android.content.Intent#ACTION_SCREEN_ON
+     * @see android.content.Intent#ACTION_SCREEN_OFF
+     */
+    public boolean isInteractive() {
         try {
-            return mService.isScreenOn();
+            return mService.isInteractive();
         } catch (RemoteException e) {
             return false;
         }
diff --git a/core/java/android/os/PowerManagerInternal.java b/core/java/android/os/PowerManagerInternal.java
new file mode 100644
index 0000000..cb3d528
--- /dev/null
+++ b/core/java/android/os/PowerManagerInternal.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+import android.view.WindowManagerPolicy;
+
+/**
+ * Power manager local system service interface.
+ *
+ * @hide Only for use within the system server.
+ */
+public abstract class PowerManagerInternal {
+    /**
+     * Used by the window manager to override the screen brightness based on the
+     * current foreground activity.
+     *
+     * This method must only be called by the window manager.
+     *
+     * @param brightness The overridden brightness, or -1 to disable the override.
+     */
+    public abstract void setScreenBrightnessOverrideFromWindowManager(int brightness);
+
+    /**
+     * Used by the window manager to override the button brightness based on the
+     * current foreground activity.
+     *
+     * This method must only be called by the window manager.
+     *
+     * @param brightness The overridden brightness, or -1 to disable the override.
+     */
+    public abstract void setButtonBrightnessOverrideFromWindowManager(int brightness);
+
+    /**
+     * Used by the window manager to override the user activity timeout based on the
+     * current foreground activity.  It can only be used to make the timeout shorter
+     * than usual, not longer.
+     *
+     * This method must only be called by the window manager.
+     *
+     * @param timeoutMillis The overridden timeout, or -1 to disable the override.
+     */
+    public abstract void setUserActivityTimeoutOverrideFromWindowManager(long timeoutMillis);
+
+    // TODO: Remove this and retrieve as a local service instead.
+    public abstract void setPolicy(WindowManagerPolicy policy);
+}
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 28797ce..112ec1d 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -939,19 +939,6 @@
     }
 
     /**
-     * Set the out-of-memory badness adjustment for a process.
-     * 
-     * @param pid The process identifier to set.
-     * @param amt Adjustment value -- linux allows -16 to +15.
-     * 
-     * @return Returns true if the underlying system supports this
-     *         feature, else false.
-     *         
-     * {@hide}
-     */
-    public static final native boolean setOomAdj(int pid, int amt);
-
-    /**
      * Adjust the swappiness level for a process.
      *
      * @param pid The process identifier to set.
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index b692ffde..f671ed9 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -338,11 +338,11 @@
     }
 
     /**
-     * Reboots the device and wipes the user data partition.  This is
-     * sometimes called a "factory reset", which is something of a
-     * misnomer because the system partition is not restored to its
-     * factory state.
-     * Requires the {@link android.Manifest.permission#REBOOT} permission.
+     * Reboots the device and wipes the user data and cache
+     * partitions.  This is sometimes called a "factory reset", which
+     * is something of a misnomer because the system partition is not
+     * restored to its factory state.  Requires the
+     * {@link android.Manifest.permission#REBOOT} permission.
      *
      * @param context  the Context to use
      *
@@ -350,6 +350,28 @@
      * fails, or if the reboot itself fails.
      */
     public static void rebootWipeUserData(Context context) throws IOException {
+        rebootWipeUserData(context, false);
+    }
+
+    /**
+     * Reboots the device and wipes the user data and cache
+     * partitions.  This is sometimes called a "factory reset", which
+     * is something of a misnomer because the system partition is not
+     * restored to its factory state.  Requires the
+     * {@link android.Manifest.permission#REBOOT} permission.
+     *
+     * @param context   the Context to use
+     * @param shutdown  if true, the device will be powered down after
+     *                  the wipe completes, rather than being rebooted
+     *                  back to the regular system.
+     *
+     * @throws IOException  if writing the recovery command file
+     * fails, or if the reboot itself fails.
+     *
+     * @hide
+     */
+    public static void rebootWipeUserData(Context context, boolean shutdown)
+        throws IOException {
         final ConditionVariable condition = new ConditionVariable();
 
         Intent intent = new Intent("android.intent.action.MASTER_CLEAR_NOTIFICATION");
@@ -365,7 +387,13 @@
         // Block until the ordered broadcast has completed.
         condition.block();
 
-        bootCommand(context, "--wipe_data\n--locale=" + Locale.getDefault().toString());
+        String shutdownArg = "";
+        if (shutdown) {
+            shutdownArg = "--shutdown_after\n";
+        }
+
+        bootCommand(context, shutdownArg + "--wipe_data\n--locale=" +
+                    Locale.getDefault().toString());
     }
 
     /**
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index d794ca6..ea71ad8 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -1449,7 +1449,11 @@
         if (policy.classInstanceLimit.size() == 0) {
             return;
         }
-        Runtime.getRuntime().gc();
+
+        System.gc();
+        System.runFinalization();
+        System.gc();
+
         // Note: classInstanceLimit is immutable, so this is lock-free
         for (Map.Entry<Class, Integer> entry : policy.classInstanceLimit.entrySet()) {
             Class klass = entry.getKey();
@@ -2005,7 +2009,10 @@
         // noticeably less responsive during orientation changes when activities are
         // being restarted.  Granted, it is only a problem when StrictMode is enabled
         // but it is annoying.
-        Runtime.getRuntime().gc();
+
+        System.gc();
+        System.runFinalization();
+        System.gc();
 
         long instances = VMDebug.countInstancesOfClass(klass, false);
         if (instances > limit) {
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index f69cad0..457afcc 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -109,14 +109,18 @@
      * An intent to perform a search for music media and automatically play content from the
      * result when possible. This can be fired, for example, by the result of a voice recognition
      * command to listen to music.
-     * <p>
-     * Contains the {@link android.app.SearchManager#QUERY} extra, which is a string
-     * that can contain any type of unstructured music search, like the name of an artist,
-     * an album, a song, a genre, or any combination of these.
-     * <p>
-     * Because this intent includes an open-ended unstructured search string, it makes the most
-     * sense for apps that can support large-scale search of music, such as services connected
-     * to an online database of music which can be streamed and played on the device.
+     * <p>This intent always includes the {@link android.provider.MediaStore#EXTRA_MEDIA_FOCUS}
+     * and {@link android.app.SearchManager#QUERY} extras. The
+     * {@link android.provider.MediaStore#EXTRA_MEDIA_FOCUS} extra determines the search mode, and
+     * the value of the {@link android.app.SearchManager#QUERY} extra depends on the search mode.
+     * For more information about the search modes for this intent, see
+     * <a href="{@docRoot}guide/components/intents-common.html#PlaySearch">Play music based
+     * on a search query</a> in <a href="{@docRoot}guide/components/intents-common.html">Common
+     * Intents</a>.</p>
+     *
+     * <p>This intent makes the most sense for apps that can support large-scale search of music,
+     * such as services connected to an online database of music which can be streamed and played
+     * on the device.</p>
      */
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String INTENT_ACTION_MEDIA_PLAY_FROM_SEARCH =
diff --git a/core/java/android/service/dreams/DozeHardware.java b/core/java/android/service/dreams/DozeHardware.java
new file mode 100644
index 0000000..b5e7f43
--- /dev/null
+++ b/core/java/android/service/dreams/DozeHardware.java
@@ -0,0 +1,77 @@
+/**
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.service.dreams;
+
+import android.os.RemoteException;
+import android.util.Log;
+
+/**
+ * Provides access to low-level hardware features that a dream may use to provide
+ * a richer user experience while dozing.
+ * <p>
+ * This class contains functions that should be called by the dream to configure
+ * hardware before starting to doze and allowing the application processor to suspend.
+ * For example, the dream may provide the hardware with enough information to render
+ * some content on its own without any further assistance from the application processor.
+ * </p><p>
+ * This object is obtained by calling {@link DreamService#getDozeHardware()}.
+ * </p>
+ *
+ * @hide experimental
+ */
+public final class DozeHardware {
+    private static final String TAG = "DozeHardware";
+
+    public static final String MSG_ENABLE_MCU = "enable_mcu";
+
+    public static final byte[] VALUE_ON = "on".getBytes();
+    public static final byte[] VALUE_OFF = "off".getBytes();
+
+    private final IDozeHardware mHardware;
+
+    DozeHardware(IDozeHardware hardware) {
+        mHardware = hardware;
+    }
+
+    /**
+     * Sets whether to enable the microcontroller.
+     *
+     * @param enable If true, enables the MCU otherwise disables it.
+     */
+    public void setEnableMcu(boolean enable) {
+        sendMessage(MSG_ENABLE_MCU, enable ? VALUE_ON : VALUE_OFF);
+    }
+
+    /**
+     * Sends a message to the doze hardware module.
+     *
+     * @param msg The name of the message to send.
+     * @param arg An optional argument data blob, may be null.
+     * @return A result data blob, may be null.
+     */
+    public byte[] sendMessage(String msg, byte[] arg) {
+        if (msg == null) {
+            throw new IllegalArgumentException("msg must not be null");
+        }
+
+        try {
+            return mHardware.sendMessage(msg, arg);
+        } catch (RemoteException ex) {
+            Log.e(TAG, "Failed to send message to doze hardware module.", ex);
+            return null;
+        }
+    }
+}
diff --git a/core/java/android/service/dreams/DreamManagerInternal.java b/core/java/android/service/dreams/DreamManagerInternal.java
new file mode 100644
index 0000000..9f7ddba
--- /dev/null
+++ b/core/java/android/service/dreams/DreamManagerInternal.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.dreams;
+
+/**
+ * Dream manager local system service interface.
+ *
+ * @hide Only for use within the system server.
+ */
+public abstract class DreamManagerInternal {
+    /**
+     * Called by the power manager to start a dream.
+     */
+    public abstract void startDream(boolean doze);
+
+    /**
+     * Called by the power manager to stop a dream.
+     */
+    public abstract void stopDream();
+
+    /**
+     * Called by the power manager to determine whether a dream is running.
+     */
+    public abstract boolean isDreaming();
+}
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index f6b6c89..b02a79d 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -20,12 +20,14 @@
 
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
+import android.app.AlarmManager;
 import android.app.Service;
 import android.content.Intent;
 import android.graphics.PixelFormat;
 import android.graphics.drawable.ColorDrawable;
 import android.os.Handler;
 import android.os.IBinder;
+import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.util.Slog;
 import android.view.ActionMode;
@@ -42,6 +44,8 @@
 import android.view.accessibility.AccessibilityEvent;
 
 import com.android.internal.policy.PolicyManager;
+import com.android.internal.util.DumpUtils;
+import com.android.internal.util.DumpUtils.Dump;
 
 /**
  * Extend this class to implement a custom dream (available to the user as a "Daydream").
@@ -145,19 +149,26 @@
      */
     public static final String DREAM_META_DATA = "android.service.dream";
 
+    private final IDreamManager mSandman;
     private final Handler mHandler = new Handler();
     private IBinder mWindowToken;
     private Window mWindow;
-    private WindowManager mWindowManager;
-    private IDreamManager mSandman;
-    private boolean mInteractive = false;
+    private boolean mInteractive;
     private boolean mLowProfile = true;
-    private boolean mFullscreen = false;
+    private boolean mFullscreen;
     private boolean mScreenBright = true;
+    private boolean mStarted;
     private boolean mFinished;
+    private boolean mCanDoze;
+    private boolean mDozing;
+    private DozeHardware mDozeHardware;
 
     private boolean mDebug = false;
 
+    public DreamService() {
+        mSandman = IDreamManager.Stub.asInterface(ServiceManager.getService(DREAM_SERVICE));
+    }
+
     /**
      * @hide
      */
@@ -325,7 +336,7 @@
      * @return The current window manager, or null if the dream is not started.
      */
     public WindowManager getWindowManager() {
-        return mWindowManager;
+        return mWindow != null ? mWindow.getWindowManager() : null;
     }
 
     /**
@@ -444,9 +455,11 @@
      * correct interactions with it (seeing when it is cleared etc).
      */
     public void setLowProfile(boolean lowProfile) {
-        mLowProfile = lowProfile;
-        int flag = View.SYSTEM_UI_FLAG_LOW_PROFILE;
-        applySystemUiVisibilityFlags(mLowProfile ? flag : 0, flag);
+        if (mLowProfile != lowProfile) {
+            mLowProfile = lowProfile;
+            int flag = View.SYSTEM_UI_FLAG_LOW_PROFILE;
+            applySystemUiVisibilityFlags(mLowProfile ? flag : 0, flag);
+        }
     }
 
     /**
@@ -467,9 +480,11 @@
      * will be cleared.
      */
     public void setFullscreen(boolean fullscreen) {
-        mFullscreen = fullscreen;
-        int flag = WindowManager.LayoutParams.FLAG_FULLSCREEN;
-        applyWindowFlags(mFullscreen ? flag : 0, flag);
+        if (mFullscreen != fullscreen) {
+            mFullscreen = fullscreen;
+            int flag = WindowManager.LayoutParams.FLAG_FULLSCREEN;
+            applyWindowFlags(mFullscreen ? flag : 0, flag);
+        }
     }
 
     /**
@@ -487,14 +502,16 @@
      * @param screenBright True to keep the screen bright while dreaming.
      */
     public void setScreenBright(boolean screenBright) {
-        mScreenBright = screenBright;
-        int flag = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
-        applyWindowFlags(mScreenBright ? flag : 0, flag);
+        if (mScreenBright != screenBright) {
+            mScreenBright = screenBright;
+            int flag = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
+            applyWindowFlags(mScreenBright ? flag : 0, flag);
+        }
     }
 
     /**
-     * Returns whether or not this dream keeps the screen bright while dreaming. Defaults to false,
-     * allowing the screen to dim if necessary.
+     * Returns whether or not this dream keeps the screen bright while dreaming.
+     * Defaults to false, allowing the screen to dim if necessary.
      *
      * @see #setScreenBright(boolean)
      */
@@ -503,6 +520,119 @@
     }
 
     /**
+     * Returns true if this dream is allowed to doze.
+     * <p>
+     * The value returned by this method is only meaningful when the dream has started.
+     * </p>
+     *
+     * @return True if this dream can doze.
+     * @see #startDozing
+     * @hide experimental
+     */
+    public boolean canDoze() {
+        return mCanDoze;
+    }
+
+    /**
+     * Starts dozing, entering a deep dreamy sleep.
+     * <p>
+     * Dozing enables the system to conserve power while the user is not actively interacting
+     * with the device.  While dozing, the display will remain on in a low-power state
+     * and will continue to show its previous contents but the application processor and
+     * other system components will be allowed to suspend when possible.
+     * </p><p>
+     * While the application processor is suspended, the dream may stop executing code
+     * for long periods of time.  Prior to being suspended, the dream may schedule periodic
+     * wake-ups to render new content by scheduling an alarm with the {@link AlarmManager}.
+     * The dream may also keep the CPU awake by acquiring a
+     * {@link android.os.PowerManager#PARTIAL_WAKE_LOCK partial wake lock} when necessary.
+     * Note that since the purpose of doze mode is to conserve power (especially when
+     * running on battery), the dream should not wake the CPU very often or keep it
+     * awake for very long.
+     * </p><p>
+     * It is a good idea to call this method some time after the dream's entry animation
+     * has completed and the dream is ready to doze.  It is important to completely
+     * finish all of the work needed before dozing since the application processor may
+     * be suspended at any moment once this method is called unless other wake locks
+     * are being held.
+     * </p><p>
+     * Call {@link #stopDozing} or {@link #finish} to stop dozing.
+     * </p>
+     *
+     * @see #stopDozing
+     * @hide experimental
+     */
+    public void startDozing() {
+        if (mCanDoze && !mDozing) {
+            mDozing = true;
+            try {
+                mSandman.startDozing(mWindowToken);
+            } catch (RemoteException ex) {
+                // system server died
+            }
+        }
+    }
+
+    /**
+     * Stops dozing, returns to active dreaming.
+     * <p>
+     * This method reverses the effect of {@link #startDozing}.  From this moment onward,
+     * the application processor will be kept awake as long as the dream is running
+     * or until the dream starts dozing again.
+     * </p>
+     *
+     * @see #startDozing
+     * @hide experimental
+     */
+    public void stopDozing() {
+        if (mDozing) {
+            mDozing = false;
+            try {
+                mSandman.stopDozing(mWindowToken);
+            } catch (RemoteException ex) {
+                // system server died
+            }
+        }
+    }
+
+    /**
+     * Returns true if the dream will allow the system to enter a low-power state while
+     * it is running without actually turning off the screen.  Defaults to false,
+     * keeping the application processor awake while the dream is running.
+     *
+     * @return True if the dream is dozing.
+     *
+     * @see #setDozing(boolean)
+     * @hide experimental
+     */
+    public boolean isDozing() {
+        return mDozing;
+    }
+
+    /**
+     * Gets an object that may be used to access low-level hardware features that a
+     * dream may use to provide a richer user experience while dozing.
+     *
+     * @return An instance of {@link DozeHardware} or null if this device does not offer
+     * hardware support for dozing.
+     *
+     * @hide experimental
+     */
+    public DozeHardware getDozeHardware() {
+        if (mCanDoze && mDozeHardware == null && mWindowToken != null) {
+            try {
+                IDozeHardware hardware = mSandman.getDozeHardware(mWindowToken);
+                if (hardware != null) {
+                    mDozeHardware = new DozeHardware(hardware);
+                }
+            } catch (RemoteException ex) {
+                // system server died
+            }
+        }
+        return mDozeHardware;
+    }
+
+    /**
      * Called when this Dream is constructed.
      */
     @Override
@@ -536,7 +666,11 @@
     }
 
     /**
-     * Stops the dream, detaches from the window, and wakes up.
+     * Stops the dream and detaches from the window.
+     * <p>
+     * When the dream ends, the system will be allowed to go to sleep fully unless there
+     * is a reason for it to be awake such as recent user activity or wake locks being held.
+     * </p>
      */
     public final void finish() {
         if (mDebug) Slog.v(TAG, "finish()");
@@ -557,41 +691,31 @@
 
     // end public api
 
-    private void loadSandman() {
-        mSandman = IDreamManager.Stub.asInterface(ServiceManager.getService(DREAM_SERVICE));
-    }
-
     /**
      * Called by DreamController.stopDream() when the Dream is about to be unbound and destroyed.
      *
      * Must run on mHandler.
      */
     private final void detach() {
-        if (mWindow == null) {
-            // already detached!
-            return;
-        }
-
-        try {
+        if (mStarted) {
+            if (mDebug) Slog.v(TAG, "detach(): Calling onDreamingStopped()");
+            mStarted = false;
             onDreamingStopped();
-        } catch (Throwable t) {
-            Slog.w(TAG, "Crashed in onDreamingStopped()", t);
-            // we were going to stop anyway
         }
 
-        if (mDebug) Slog.v(TAG, "detach(): Removing window from window manager");
-        try {
+        if (mWindow != null) {
             // force our window to be removed synchronously
-            mWindowManager.removeViewImmediate(mWindow.getDecorView());
+            if (mDebug) Slog.v(TAG, "detach(): Removing window from window manager");
+            mWindow.getWindowManager().removeViewImmediate(mWindow.getDecorView());
+            mWindow = null;
+        }
+
+        if (mWindowToken != null) {
             // the following will print a log message if it finds any other leaked windows
             WindowManagerGlobal.getInstance().closeAll(mWindowToken,
                     this.getClass().getName(), "Dream");
-        } catch (Throwable t) {
-            Slog.w(TAG, "Crashed removing window view", t);
+            mWindowToken = null;
         }
-
-        mWindow = null;
-        mWindowToken = null;
     }
 
     /**
@@ -601,18 +725,26 @@
      *
      * @param windowToken A window token that will allow a window to be created in the correct layer.
      */
-    private final void attach(IBinder windowToken) {
+    private final void attach(IBinder windowToken, boolean canDoze) {
         if (mWindowToken != null) {
             Slog.e(TAG, "attach() called when already attached with token=" + mWindowToken);
             return;
         }
+        if (mFinished) {
+            Slog.w(TAG, "attach() called after dream already finished");
+            try {
+                mSandman.finishSelf(windowToken);
+            } catch (RemoteException ex) {
+                // system server died
+            }
+            return;
+        }
 
         if (mDebug) Slog.v(TAG, "Attached on thread " + Thread.currentThread().getId());
 
-        if (mSandman == null) {
-            loadSandman();
-        }
         mWindowToken = windowToken;
+        mCanDoze = canDoze;
+
         mWindow = PolicyManager.makeNewWindow(this);
         mWindow.setCallback(this);
         mWindow.requestFeature(Window.FEATURE_NO_TITLE);
@@ -635,33 +767,35 @@
                     | (mScreenBright ? WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON : 0)
                     );
         mWindow.setAttributes(lp);
-
-        if (mDebug) Slog.v(TAG, "Created and attached window: " + mWindow);
-
         mWindow.setWindowManager(null, windowToken, "dream", true);
-        mWindowManager = mWindow.getWindowManager();
 
-        if (mDebug) Slog.v(TAG, "Window added on thread " + Thread.currentThread().getId());
+        applySystemUiVisibilityFlags(
+                (mLowProfile ? View.SYSTEM_UI_FLAG_LOW_PROFILE : 0),
+                View.SYSTEM_UI_FLAG_LOW_PROFILE);
+
         try {
-            applySystemUiVisibilityFlags(
-                    (mLowProfile ? View.SYSTEM_UI_FLAG_LOW_PROFILE : 0),
-                    View.SYSTEM_UI_FLAG_LOW_PROFILE);
             getWindowManager().addView(mWindow.getDecorView(), mWindow.getAttributes());
-        } catch (Throwable t) {
-            Slog.w(TAG, "Crashed adding window view", t);
-            safelyFinish();
+        } catch (WindowManager.BadTokenException ex) {
+            // This can happen because the dream manager service will remove the token
+            // immediately without necessarily waiting for the dream to start.
+            // We should receive a finish message soon.
+            Slog.i(TAG, "attach() called after window token already removed, dream will "
+                    + "finish soon");
+            mWindow = null;
             return;
         }
 
-        // start it up
+        // We need to defer calling onDreamingStarted until after onWindowAttached,
+        // which is posted to the handler by addView, so we post onDreamingStarted
+        // to the handler also.  Need to watch out here in case detach occurs before
+        // this callback is invoked.
         mHandler.post(new Runnable() {
             @Override
             public void run() {
-                try {
+                if (mWindow != null) {
+                    if (mDebug) Slog.v(TAG, "Calling onDreamingStarted()");
+                    mStarted = true;
                     onDreamingStarted();
-                } catch (Throwable t) {
-                    Slog.w(TAG, "Crashed in onDreamingStarted()", t);
-                    safelyFinish();
                 }
             }
         });
@@ -669,13 +803,8 @@
 
     private void safelyFinish() {
         if (mDebug) Slog.v(TAG, "safelyFinish()");
-        try {
-            finish();
-        } catch (Throwable t) {
-            Slog.w(TAG, "Crashed in safelyFinish()", t);
-            finishInternal();
-            return;
-        }
+
+        finish();
 
         if (!mFinished) {
             Slog.w(TAG, "Bad dream, did not call super.finish()");
@@ -685,19 +814,21 @@
 
     private void finishInternal() {
         if (mDebug) Slog.v(TAG, "finishInternal() mFinished = " + mFinished);
-        if (mFinished) return;
-        try {
+
+        if (!mFinished) {
             mFinished = true;
 
-            if (mSandman != null) {
-                mSandman.finishSelf(mWindowToken);
+            if (mWindowToken == null) {
+                Slog.w(TAG, "Finish was called before the dream was attached.");
             } else {
-                Slog.w(TAG, "No dream manager found");
+                try {
+                    mSandman.finishSelf(mWindowToken);
+                } catch (RemoteException ex) {
+                    // system server died
+                }
             }
-            stopSelf(); // if launched via any other means
 
-        } catch (Throwable t) {
-            Slog.w(TAG, "Crashed in finishInternal()", t);
+            stopSelf(); // if launched via any other means
         }
     }
 
@@ -710,7 +841,7 @@
             WindowManager.LayoutParams lp = mWindow.getAttributes();
             lp.flags = applyFlags(lp.flags, flags, mask);
             mWindow.setAttributes(lp);
-            mWindowManager.updateViewLayout(mWindow.getDecorView(), lp);
+            mWindow.getWindowManager().updateViewLayout(mWindow.getDecorView(), lp);
         }
     }
 
@@ -732,32 +863,39 @@
 
     @Override
     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        super.dump(fd, pw, args);
-
-        pw.print(TAG + ": ");
-        if (mWindowToken == null) {
-            pw.println("stopped");
-        } else {
-            pw.println("running (token=" + mWindowToken + ")");
-        }
-        pw.println("  window: " + mWindow);
-        pw.print("  flags:");
-        if (isInteractive()) pw.print(" interactive");
-        if (isLowProfile()) pw.print(" lowprofile");
-        if (isFullscreen()) pw.print(" fullscreen");
-        if (isScreenBright()) pw.print(" bright");
-        pw.println();
+        DumpUtils.dumpAsync(mHandler, new Dump() {
+            @Override
+            public void dump(PrintWriter pw) {
+                pw.print(TAG + ": ");
+                if (mWindowToken == null) {
+                    pw.println("stopped");
+                } else {
+                    pw.println("running (token=" + mWindowToken + ")");
+                }
+                pw.println("  window: " + mWindow);
+                pw.print("  flags:");
+                if (isInteractive()) pw.print(" interactive");
+                if (isLowProfile()) pw.print(" lowprofile");
+                if (isFullscreen()) pw.print(" fullscreen");
+                if (isScreenBright()) pw.print(" bright");
+                if (isDozing()) pw.print(" dozing");
+                pw.println();
+            }
+        }, pw, 1000);
     }
 
-    private class DreamServiceWrapper extends IDreamService.Stub {
-        public void attach(final IBinder windowToken) {
+    private final class DreamServiceWrapper extends IDreamService.Stub {
+        @Override
+        public void attach(final IBinder windowToken, final boolean canDoze) {
             mHandler.post(new Runnable() {
                 @Override
                 public void run() {
-                    DreamService.this.attach(windowToken);
+                    DreamService.this.attach(windowToken, canDoze);
                 }
             });
         }
+
+        @Override
         public void detach() {
             mHandler.post(new Runnable() {
                 @Override
diff --git a/services/java/com/android/server/power/DisplayBlanker.java b/core/java/android/service/dreams/IDozeHardware.aidl
similarity index 71%
copy from services/java/com/android/server/power/DisplayBlanker.java
copy to core/java/android/service/dreams/IDozeHardware.aidl
index 6072053..f5a657b 100644
--- a/services/java/com/android/server/power/DisplayBlanker.java
+++ b/core/java/android/service/dreams/IDozeHardware.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 The Android Open Source Project
+ * Copyright (C) 2014 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,12 +14,11 @@
  * limitations under the License.
  */
 
-package com.android.server.power;
+package android.service.dreams;
 
 /**
- * Blanks or unblanks all displays.
+ * @hide
  */
-interface DisplayBlanker {
-    public void blankAllDisplays();
-    public void unblankAllDisplays();
+interface IDozeHardware {
+    byte[] sendMessage(String msg, in byte[] arg);
 }
diff --git a/core/java/android/service/dreams/IDreamManager.aidl b/core/java/android/service/dreams/IDreamManager.aidl
index 1c1b390..2718e316 100644
--- a/core/java/android/service/dreams/IDreamManager.aidl
+++ b/core/java/android/service/dreams/IDreamManager.aidl
@@ -16,10 +16,11 @@
 
 package android.service.dreams;
 
+import android.content.ComponentName;
 import android.os.Bundle;
 import android.os.ParcelFileDescriptor;
-import android.content.ComponentName;
 import android.os.IBinder;
+import android.service.dreams.IDozeHardware;
 
 /** @hide */
 interface IDreamManager {
@@ -31,4 +32,7 @@
     void testDream(in ComponentName componentName);
     boolean isDreaming();
     void finishSelf(in IBinder token);
+    void startDozing(in IBinder token);
+    void stopDozing(in IBinder token);
+    IDozeHardware getDozeHardware(in IBinder token);
 }
\ No newline at end of file
diff --git a/core/java/android/service/dreams/IDreamService.aidl b/core/java/android/service/dreams/IDreamService.aidl
index 99dc0b7..bd58f1d 100644
--- a/core/java/android/service/dreams/IDreamService.aidl
+++ b/core/java/android/service/dreams/IDreamService.aidl
@@ -20,6 +20,6 @@
  * @hide
  */
 oneway interface IDreamService {
-    void attach(IBinder windowToken);
+    void attach(IBinder windowToken, boolean canDoze);
     void detach();
 }
diff --git a/core/java/android/service/notification/INotificationListener.aidl b/core/java/android/service/notification/INotificationListener.aidl
index 425fdc1..d4b29d8 100644
--- a/core/java/android/service/notification/INotificationListener.aidl
+++ b/core/java/android/service/notification/INotificationListener.aidl
@@ -21,6 +21,7 @@
 /** @hide */
 oneway interface INotificationListener
 {
+    void onListenerConnected(in String[] notificationKeys);
     void onNotificationPosted(in StatusBarNotification notification);
     void onNotificationRemoved(in StatusBarNotification notification);
 }
\ No newline at end of file
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index 2e0e59b..eb2de2c 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -83,6 +83,18 @@
      */
     public abstract void onNotificationRemoved(StatusBarNotification sbn);
 
+    /**
+     * Implement this method to learn about when the listener is enabled and connected to
+     * the notification manager.  You are safe to call {@link #getActiveNotifications(String[])
+     * at this time.
+     *
+     * @param notificationKeys The notification keys for all currently posted notifications.
+     * @hide
+     */
+    public void onListenerConnected(String[] notificationKeys) {
+        // optional
+    }
+
     private final INotificationManager getNotificationInterface() {
         if (mNoMan == null) {
             mNoMan = INotificationManager.Stub.asInterface(
@@ -112,6 +124,7 @@
      *     {@link android.app.NotificationManager#notify(String, int, android.app.Notification)}.
      */
     public final void cancelNotification(String pkg, String tag, int id) {
+        if (!isBound()) return;
         try {
             getNotificationInterface().cancelNotificationFromListener(mWrapper, pkg, tag, id);
         } catch (android.os.RemoteException ex) {
@@ -131,8 +144,24 @@
      * {@see #cancelNotification(String, String, int)}
      */
     public final void cancelAllNotifications() {
+        cancelNotifications(null /*all*/);
+    }
+
+    /**
+     * Inform the notification manager about dismissal of specific notifications.
+     * <p>
+     * Use this if your listener has a user interface that allows the user to dismiss
+     * multiple notifications at once.
+     *
+     * @param keys Notifications to dismiss, or {@code null} to dismiss all.
+     *
+     * {@see #cancelNotification(String, String, int)}
+     * @hide
+     */
+    public final void cancelNotifications(String[] keys) {
+        if (!isBound()) return;
         try {
-            getNotificationInterface().cancelAllNotificationsFromListener(mWrapper);
+            getNotificationInterface().cancelNotificationsFromListener(mWrapper, keys);
         } catch (android.os.RemoteException ex) {
             Log.v(TAG, "Unable to contact notification manager", ex);
         }
@@ -140,13 +169,26 @@
 
     /**
      * Request the list of outstanding notifications (that is, those that are visible to the
-     * current user). Useful when starting up and you don't know what's already been posted.
+     * current user). Useful when you don't know what's already been posted.
      *
      * @return An array of active notifications.
      */
     public StatusBarNotification[] getActiveNotifications() {
+        return getActiveNotifications(null /*all*/);
+    }
+
+    /**
+     * Request the list of outstanding notifications (that is, those that are visible to the
+     * current user). Useful when you don't know what's already been posted.
+     *
+     * @param keys A specific list of notification keys, or {@code null} for all.
+     * @return An array of active notifications.
+     * @hide
+     */
+    public StatusBarNotification[] getActiveNotifications(String[] keys) {
+        if (!isBound()) return null;
         try {
-            return getNotificationInterface().getActiveNotificationsFromListener(mWrapper);
+            return getNotificationInterface().getActiveNotificationsFromListener(mWrapper, keys);
         } catch (android.os.RemoteException ex) {
             Log.v(TAG, "Unable to contact notification manager", ex);
         }
@@ -161,6 +203,14 @@
         return mWrapper;
     }
 
+    private boolean isBound() {
+        if (mWrapper == null) {
+            Log.w(TAG, "Notification listener service not yet bound.");
+            return false;
+        }
+        return true;
+    }
+
     private class INotificationListenerWrapper extends INotificationListener.Stub {
         @Override
         public void onNotificationPosted(StatusBarNotification sbn) {
@@ -178,5 +228,13 @@
                 Log.w(TAG, "Error running onNotificationRemoved", t);
             }
         }
+        @Override
+        public void onListenerConnected(String[] notificationKeys) {
+            try {
+                NotificationListenerService.this.onListenerConnected(notificationKeys);
+            } catch (Throwable t) {
+                Log.w(TAG, "Error running onListenerConnected", t);
+            }
+        }
     }
 }
diff --git a/core/java/android/service/notification/StatusBarNotification.java b/core/java/android/service/notification/StatusBarNotification.java
index b5b9e14..96dd143d 100644
--- a/core/java/android/service/notification/StatusBarNotification.java
+++ b/core/java/android/service/notification/StatusBarNotification.java
@@ -29,6 +29,7 @@
     private final String pkg;
     private final int id;
     private final String tag;
+    private final String key;
 
     private final int uid;
     private final String basePkg;
@@ -70,6 +71,7 @@
         this.notification.setUser(user);
 
         this.postTime = postTime;
+        this.key = key();
     }
 
     public StatusBarNotification(Parcel in) {
@@ -88,6 +90,11 @@
         this.user = UserHandle.readFromParcel(in);
         this.notification.setUser(this.user);
         this.postTime = in.readLong();
+        this.key = key();
+    }
+
+    private String key() {
+        return pkg + '|' + basePkg + '|' + id + '|' + tag + '|' + uid;
     }
 
     public void writeToParcel(Parcel out, int flags) {
@@ -148,9 +155,9 @@
     @Override
     public String toString() {
         return String.format(
-                "StatusBarNotification(pkg=%s user=%s id=%d tag=%s score=%d: %s)",
+                "StatusBarNotification(pkg=%s user=%s id=%d tag=%s score=%d key=%s: %s)",
                 this.pkg, this.user, this.id, this.tag,
-                this.score, this.notification);
+                this.score, this.key, this.notification);
     }
 
     /** Convenience method to check the notification's flags for
@@ -230,4 +237,11 @@
     public int getScore() {
         return score;
     }
+
+    /**
+     * A unique instance key for this notification record.
+     */
+    public String getKey() {
+        return key;
+    }
 }
diff --git a/core/java/android/speech/SpeechRecognizer.java b/core/java/android/speech/SpeechRecognizer.java
index 94aedbd..91c3799 100644
--- a/core/java/android/speech/SpeechRecognizer.java
+++ b/core/java/android/speech/SpeechRecognizer.java
@@ -409,7 +409,7 @@
      * Internal wrapper of IRecognitionListener which will propagate the results to
      * RecognitionListener
      */
-    private class InternalListener extends IRecognitionListener.Stub {
+    private static class InternalListener extends IRecognitionListener.Stub {
         private RecognitionListener mInternalListener;
 
         private final static int MSG_BEGINNING_OF_SPEECH = 1;
diff --git a/core/java/android/text/BoringLayout.java b/core/java/android/text/BoringLayout.java
index 77cd71e..6f00707 100644
--- a/core/java/android/text/BoringLayout.java
+++ b/core/java/android/text/BoringLayout.java
@@ -188,10 +188,6 @@
             spacing = metrics.descent - metrics.ascent;
         }
 
-        if (spacingmult != 1 || spacingadd != 0) {
-            spacing = (int)(spacing * spacingmult + spacingadd + 0.5f);
-        }
-
         mBottom = spacing;
 
         if (includepad) {
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index e7d6fda..814326c 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -633,7 +633,11 @@
             bottom = fm.bottom;
         }
 
-        if (j == 0) {
+        boolean firstLine = (j == 0);
+        boolean currentLineIsTheLastVisibleOne = (j + 1 == mMaximumVisibleLineCount);
+        boolean lastLine = currentLineIsTheLastVisibleOne || (end == bufEnd);
+
+        if (firstLine) {
             if (trackPad) {
                 mTopPadding = top - above;
             }
@@ -642,7 +646,10 @@
                 above = top;
             }
         }
-        if (end == bufEnd) {
+
+        int extra;
+
+        if (lastLine) {
             if (trackPad) {
                 mBottomPadding = bottom - below;
             }
@@ -652,9 +659,8 @@
             }
         }
 
-        int extra;
 
-        if (needMultiply) {
+        if (needMultiply && !lastLine) {
             double ex = (below - above) * (spacingmult - 1) + spacingadd;
             if (ex >= 0) {
                 extra = (int)(ex + EXTRA_ROUNDING);
@@ -691,8 +697,6 @@
         if (ellipsize != null) {
             // If there is only one line, then do any type of ellipsis except when it is MARQUEE
             // if there are multiple lines, just allow END ellipsis on the last line
-            boolean firstLine = (j == 0);
-            boolean currentLineIsTheLastVisibleOne = (j + 1 == mMaximumVisibleLineCount);
             boolean forceEllipsis = moreChars && (mLineCount + 1 == mMaximumVisibleLineCount);
 
             boolean doEllipsis =
diff --git a/core/java/android/util/TypedValue.java b/core/java/android/util/TypedValue.java
index ed45298..931fb81 100644
--- a/core/java/android/util/TypedValue.java
+++ b/core/java/android/util/TypedValue.java
@@ -290,18 +290,14 @@
         return -1;
     }
 
+    /**
+     * @hide Was accidentally exposed in API level 1 for debugging purposes.
+     * Kept for compatibility just in case although the debugging code has been removed.
+     */
+    @Deprecated
     public static float complexToDimensionNoisy(int data, DisplayMetrics metrics)
     {
-        float res = complexToDimension(data, metrics);
-        System.out.println(
-            "Dimension (0x" + ((data>>TypedValue.COMPLEX_MANTISSA_SHIFT)
-                               & TypedValue.COMPLEX_MANTISSA_MASK)
-            + "*" + (RADIX_MULTS[(data>>TypedValue.COMPLEX_RADIX_SHIFT)
-                                & TypedValue.COMPLEX_RADIX_MASK] / MANTISSA_MULT)
-            + ")" + DIMENSION_UNIT_STRS[(data>>COMPLEX_UNIT_SHIFT)
-                                & COMPLEX_UNIT_MASK]
-            + " = " + res);
-        return res;
+        return complexToDimension(data, metrics);
     }
 
     /**
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 7d310a2..c4494f4 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -204,6 +204,36 @@
     public static final int TYPE_VIRTUAL = 5;
 
     /**
+     * Display state: The display state is unknown.
+     *
+     * @see #getState
+     */
+    public static final int STATE_UNKNOWN = 0;
+
+    /**
+     * Display state: The display is off.
+     *
+     * @see #getState
+     */
+    public static final int STATE_OFF = 1;
+
+    /**
+     * Display state: The display is on.
+     *
+     * @see #getState
+     */
+    public static final int STATE_ON = 2;
+
+    /**
+     * Display state: The display is dozing in a low-power state; it may be showing
+     * system-provided content while the device is in a non-interactive state.
+     *
+     * @see #getState
+     * @see android.os.PowerManager#isInteractive
+     */
+    public static final int STATE_DOZING = 3;
+
+    /**
      * Internal method to create a display.
      * Applications should use {@link android.view.WindowManager#getDefaultDisplay()}
      * or {@link android.hardware.display.DisplayManager#getDisplay}
@@ -628,6 +658,19 @@
     }
 
     /**
+     * Gets the state of the display, such as whether it is on or off.
+     *
+     * @return The state of the display: one of {@link #STATE_OFF}, {@link #STATE_ON},
+     * {@link #STATE_DOZING}, or {@link #STATE_UNKNOWN}.
+     */
+    public int getState() {
+        synchronized (this) {
+            updateDisplayInfoLocked();
+            return mIsValid ? mDisplayInfo.state : STATE_UNKNOWN;
+        }
+    }
+
+    /**
      * Returns true if the specified UID has access to this display.
      * @hide
      */
@@ -718,5 +761,22 @@
                 return Integer.toString(type);
         }
     }
-}
 
+    /**
+     * @hide
+     */
+    public static String stateToString(int state) {
+        switch (state) {
+            case STATE_UNKNOWN:
+                return "UNKNOWN";
+            case STATE_OFF:
+                return "OFF";
+            case STATE_ON:
+                return "ON";
+            case STATE_DOZING:
+                return "DOZING";
+            default:
+                return Integer.toString(state);
+        }
+    }
+}
diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java
index 8944207..5f840d3 100644
--- a/core/java/android/view/DisplayInfo.java
+++ b/core/java/android/view/DisplayInfo.java
@@ -180,6 +180,11 @@
     public float physicalYDpi;
 
     /**
+     * The state of the display, such as {@link android.view.Display#STATE_ON}.
+     */
+    public int state;
+
+    /**
      * The UID of the application that owns this display, or zero if it is owned by the system.
      * <p>
      * If the display is private, then only the owner can use it.
@@ -248,6 +253,7 @@
                 && logicalDensityDpi == other.logicalDensityDpi
                 && physicalXDpi == other.physicalXDpi
                 && physicalYDpi == other.physicalYDpi
+                && state == other.state
                 && ownerUid == other.ownerUid
                 && Objects.equal(ownerPackageName, other.ownerPackageName);
     }
@@ -280,6 +286,7 @@
         logicalDensityDpi = other.logicalDensityDpi;
         physicalXDpi = other.physicalXDpi;
         physicalYDpi = other.physicalYDpi;
+        state = other.state;
         ownerUid = other.ownerUid;
         ownerPackageName = other.ownerPackageName;
     }
@@ -307,6 +314,7 @@
         logicalDensityDpi = source.readInt();
         physicalXDpi = source.readFloat();
         physicalYDpi = source.readFloat();
+        state = source.readInt();
         ownerUid = source.readInt();
         ownerPackageName = source.readString();
     }
@@ -335,6 +343,7 @@
         dest.writeInt(logicalDensityDpi);
         dest.writeFloat(physicalXDpi);
         dest.writeFloat(physicalYDpi);
+        dest.writeInt(state);
         dest.writeInt(ownerUid);
         dest.writeString(ownerPackageName);
     }
@@ -431,7 +440,7 @@
         sb.append(smallestNominalAppHeight);
         sb.append(", ");
         sb.append(refreshRate);
-        sb.append(" fps, rotation");
+        sb.append(" fps, rotation ");
         sb.append(rotation);
         sb.append(", density ");
         sb.append(logicalDensityDpi);
@@ -446,6 +455,8 @@
         if (address != null) {
             sb.append(", address ").append(address);
         }
+        sb.append(", state ");
+        sb.append(Display.stateToString(state));
         if (ownerUid != 0 || ownerPackageName != null) {
             sb.append(", owner ").append(ownerPackageName);
             sb.append(" (uid ").append(ownerUid).append(")");
diff --git a/core/java/android/view/IWindow.aidl b/core/java/android/view/IWindow.aidl
index 8ec07ef..3670eed 100644
--- a/core/java/android/view/IWindow.aidl
+++ b/core/java/android/view/IWindow.aidl
@@ -50,7 +50,6 @@
     void moved(int newX, int newY);
     void dispatchAppVisibility(boolean visible);
     void dispatchGetNewSurface();
-    void dispatchScreenState(boolean on);
 
     /**
      * Tell the window that it is either gaining or losing focus.  Keep it up
diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java
index e829116..88c722b 100644
--- a/core/java/android/view/InputDevice.java
+++ b/core/java/android/view/InputDevice.java
@@ -17,6 +17,7 @@
 package android.view;
 
 import android.content.Context;
+import android.hardware.input.InputDeviceIdentifier;
 import android.hardware.input.InputManager;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -49,6 +50,7 @@
     private final int mVendorId;
     private final int mProductId;
     private final String mDescriptor;
+    private final InputDeviceIdentifier mIdentifier;
     private final boolean mIsExternal;
     private final int mSources;
     private final int mKeyboardType;
@@ -61,7 +63,7 @@
 
     /**
      * A mask for input source classes.
-     * 
+     *
      * Each distinct input source constant has one or more input source class bits set to
      * specify the desired interpretation for its input events.
      */
@@ -77,46 +79,46 @@
     /**
      * The input source has buttons or keys.
      * Examples: {@link #SOURCE_KEYBOARD}, {@link #SOURCE_DPAD}.
-     * 
+     *
      * A {@link KeyEvent} should be interpreted as a button or key press.
-     * 
+     *
      * Use {@link #getKeyCharacterMap} to query the device's button and key mappings.
      */
     public static final int SOURCE_CLASS_BUTTON = 0x00000001;
-    
+
     /**
      * The input source is a pointing device associated with a display.
      * Examples: {@link #SOURCE_TOUCHSCREEN}, {@link #SOURCE_MOUSE}.
-     * 
+     *
      * A {@link MotionEvent} should be interpreted as absolute coordinates in
      * display units according to the {@link View} hierarchy.  Pointer down/up indicated when
      * the finger touches the display or when the selection button is pressed/released.
-     * 
+     *
      * Use {@link #getMotionRange} to query the range of the pointing device.  Some devices permit
      * touches outside the display area so the effective range may be somewhat smaller or larger
      * than the actual display size.
      */
     public static final int SOURCE_CLASS_POINTER = 0x00000002;
-    
+
     /**
      * The input source is a trackball navigation device.
      * Examples: {@link #SOURCE_TRACKBALL}.
-     * 
+     *
      * A {@link MotionEvent} should be interpreted as relative movements in device-specific
      * units used for navigation purposes.  Pointer down/up indicates when the selection button
      * is pressed/released.
-     * 
+     *
      * Use {@link #getMotionRange} to query the range of motion.
      */
     public static final int SOURCE_CLASS_TRACKBALL = 0x00000004;
-    
+
     /**
      * The input source is an absolute positioning device not associated with a display
      * (unlike {@link #SOURCE_CLASS_POINTER}).
-     * 
+     *
      * A {@link MotionEvent} should be interpreted as absolute coordinates in
      * device-specific surface units.
-     * 
+     *
      * Use {@link #getMotionRange} to query the range of positions.
      */
     public static final int SOURCE_CLASS_POSITION = 0x00000008;
@@ -134,7 +136,7 @@
      * The input source is unknown.
      */
     public static final int SOURCE_UNKNOWN = 0x00000000;
-    
+
     /**
      * The input source is a keyboard.
      *
@@ -145,10 +147,10 @@
      * @see #SOURCE_CLASS_BUTTON
      */
     public static final int SOURCE_KEYBOARD = 0x00000100 | SOURCE_CLASS_BUTTON;
-    
+
     /**
      * The input source is a DPad.
-     * 
+     *
      * @see #SOURCE_CLASS_BUTTON
      */
     public static final int SOURCE_DPAD = 0x00000200 | SOURCE_CLASS_BUTTON;
@@ -163,16 +165,16 @@
 
     /**
      * The input source is a touch screen pointing device.
-     * 
+     *
      * @see #SOURCE_CLASS_POINTER
      */
     public static final int SOURCE_TOUCHSCREEN = 0x00001000 | SOURCE_CLASS_POINTER;
-    
+
     /**
      * The input source is a mouse pointing device.
      * This code is also used for other mouse-like pointing devices such as trackpads
      * and trackpoints.
-     * 
+     *
      * @see #SOURCE_CLASS_POINTER
      */
     public static final int SOURCE_MOUSE = 0x00002000 | SOURCE_CLASS_POINTER;
@@ -199,15 +201,15 @@
 
     /**
      * The input source is a trackball.
-     * 
+     *
      * @see #SOURCE_CLASS_TRACKBALL
      */
     public static final int SOURCE_TRACKBALL = 0x00010000 | SOURCE_CLASS_TRACKBALL;
-    
+
     /**
      * The input source is a touch pad or digitizer tablet that is not
      * associated with a display (unlike {@link #SOURCE_TOUCHSCREEN}).
-     * 
+     *
      * @see #SOURCE_CLASS_POSITION
      */
     public static final int SOURCE_TOUCHPAD = 0x00100000 | SOURCE_CLASS_POSITION;
@@ -239,7 +241,7 @@
 
     /**
      * Constant for retrieving the range of values for {@link MotionEvent#AXIS_X}.
-     * 
+     *
      * @see #getMotionRange
      * @deprecated Use {@link MotionEvent#AXIS_X} instead.
      */
@@ -248,7 +250,7 @@
 
     /**
      * Constant for retrieving the range of values for {@link MotionEvent#AXIS_Y}.
-     * 
+     *
      * @see #getMotionRange
      * @deprecated Use {@link MotionEvent#AXIS_Y} instead.
      */
@@ -257,7 +259,7 @@
 
     /**
      * Constant for retrieving the range of values for {@link MotionEvent#AXIS_PRESSURE}.
-     * 
+     *
      * @see #getMotionRange
      * @deprecated Use {@link MotionEvent#AXIS_PRESSURE} instead.
      */
@@ -266,7 +268,7 @@
 
     /**
      * Constant for retrieving the range of values for {@link MotionEvent#AXIS_SIZE}.
-     * 
+     *
      * @see #getMotionRange
      * @deprecated Use {@link MotionEvent#AXIS_SIZE} instead.
      */
@@ -275,7 +277,7 @@
 
     /**
      * Constant for retrieving the range of values for {@link MotionEvent#AXIS_TOUCH_MAJOR}.
-     * 
+     *
      * @see #getMotionRange
      * @deprecated Use {@link MotionEvent#AXIS_TOUCH_MAJOR} instead.
      */
@@ -284,7 +286,7 @@
 
     /**
      * Constant for retrieving the range of values for {@link MotionEvent#AXIS_TOUCH_MINOR}.
-     * 
+     *
      * @see #getMotionRange
      * @deprecated Use {@link MotionEvent#AXIS_TOUCH_MINOR} instead.
      */
@@ -293,7 +295,7 @@
 
     /**
      * Constant for retrieving the range of values for {@link MotionEvent#AXIS_TOOL_MAJOR}.
-     * 
+     *
      * @see #getMotionRange
      * @deprecated Use {@link MotionEvent#AXIS_TOOL_MAJOR} instead.
      */
@@ -302,7 +304,7 @@
 
     /**
      * Constant for retrieving the range of values for {@link MotionEvent#AXIS_TOOL_MINOR}.
-     * 
+     *
      * @see #getMotionRange
      * @deprecated Use {@link MotionEvent#AXIS_TOOL_MINOR} instead.
      */
@@ -311,24 +313,24 @@
 
     /**
      * Constant for retrieving the range of values for {@link MotionEvent#AXIS_ORIENTATION}.
-     * 
+     *
      * @see #getMotionRange
      * @deprecated Use {@link MotionEvent#AXIS_ORIENTATION} instead.
      */
     @Deprecated
     public static final int MOTION_RANGE_ORIENTATION = MotionEvent.AXIS_ORIENTATION;
-    
+
     /**
      * There is no keyboard.
      */
     public static final int KEYBOARD_TYPE_NONE = 0;
-    
+
     /**
      * The keyboard is not fully alphabetic.  It may be a numeric keypad or an assortment
      * of buttons that are not mapped as alphabetic keys suitable for text input.
      */
     public static final int KEYBOARD_TYPE_NON_ALPHABETIC = 1;
-    
+
     /**
      * The keyboard supports a complement of alphabetic keys.
      */
@@ -361,6 +363,7 @@
         mKeyCharacterMap = keyCharacterMap;
         mHasVibrator = hasVibrator;
         mHasButtonUnderPad = hasButtonUnderPad;
+        mIdentifier = new InputDeviceIdentifier(descriptor, vendorId, productId);
     }
 
     private InputDevice(Parcel in) {
@@ -377,6 +380,7 @@
         mKeyCharacterMap = KeyCharacterMap.CREATOR.createFromParcel(in);
         mHasVibrator = in.readInt() != 0;
         mHasButtonUnderPad = in.readInt() != 0;
+        mIdentifier = new InputDeviceIdentifier(mDescriptor, mVendorId, mProductId);
 
         for (;;) {
             int axis = in.readInt();
@@ -396,7 +400,7 @@
     public static InputDevice getDevice(int id) {
         return InputManager.getInstance().getInputDevice(id);
     }
-    
+
     /**
      * Gets the ids of all input devices in the system.
      * @return The input device ids.
@@ -441,6 +445,18 @@
     }
 
     /**
+     * The set of identifying information for type of input device. This
+     * information can be used by the system to configure appropriate settings
+     * for the device.
+     *
+     * @return The identifier object for this device
+     * @hide
+     */
+    public InputDeviceIdentifier getIdentifier() {
+        return mIdentifier;
+    }
+
+    /**
      * Gets a generation number for this input device.
      * The generation number is incremented whenever the device is reconfigured and its
      * properties may have changed.
@@ -553,7 +569,7 @@
     public String getName() {
         return mName;
     }
-    
+
     /**
      * Gets the input sources supported by this input device as a combined bitfield.
      * @return The supported input sources.
@@ -561,7 +577,20 @@
     public int getSources() {
         return mSources;
     }
-    
+
+    /**
+     * Determines whether the input device supports the given source or sources.
+     *
+     * @param source The input source or sources to check against. This can be a generic device
+     * type such as {@link InputDevice#SOURCE_MOUSE}, a more generic device class, such as
+     * {@link InputDevice#SOURCE_CLASS_POINTER}, or a combination of sources bitwise ORed together.
+     * @return Whether the device can produce all of the given sources.
+     * @hide
+     */
+    public boolean supportsSource(int source) {
+        return (mSources & source) == source;
+    }
+
     /**
      * Gets the keyboard type.
      * @return The keyboard type.
@@ -569,7 +598,7 @@
     public int getKeyboardType() {
         return mKeyboardType;
     }
-    
+
     /**
      * Gets the key character map associated with this input device.
      * @return The key character map.
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index 5a5fc10..214fd12 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -629,11 +629,19 @@
     /** Key code constant: Brightness Up key.
      * Adjusts the screen brightness up. */
     public static final int KEYCODE_BRIGHTNESS_UP   = 221;
-    /** Key code constant: Audio Track key
+    /** Key code constant: Audio Track key.
      * Switches the audio tracks. */
     public static final int KEYCODE_MEDIA_AUDIO_TRACK = 222;
+    /** Key code constant: Sleep key.
+     * Puts the device to sleep.  Behaves somewhat like {@link #KEYCODE_POWER} but it
+     * has no effect if the device is already asleep. */
+    public static final int KEYCODE_SLEEP           = 223;
+    /** Key code constant: Wakeup key.
+     * Wakes up the device.  Behaves somewhat like {@link #KEYCODE_POWER} but it
+     * has no effect if the device is already awake. */
+    public static final int KEYCODE_WAKEUP          = 224;
 
-    private static final int LAST_KEYCODE           = KEYCODE_MEDIA_AUDIO_TRACK;
+    private static final int LAST_KEYCODE = KEYCODE_WAKEUP;
 
     // NOTE: If you add a new keycode here you must also add it to:
     //  isSystem()
@@ -878,6 +886,8 @@
         names.append(KEYCODE_BRIGHTNESS_DOWN, "KEYCODE_BRIGHTNESS_DOWN");
         names.append(KEYCODE_BRIGHTNESS_UP, "KEYCODE_BRIGHTNESS_UP");
         names.append(KEYCODE_MEDIA_AUDIO_TRACK, "KEYCODE_MEDIA_AUDIO_TRACK");
+        names.append(KEYCODE_SLEEP, "KEYCODE_SLEEP");
+        names.append(KEYCODE_WAKEUP, "KEYCODE_WAKEUP");
     };
 
     // Symbolic names of all metakeys in bit order from least significant to most significant.
@@ -1157,9 +1167,13 @@
 
     /**
      * This mask is set if the device woke because of this key event.
+     *
+     * @deprecated This flag will never be set by the system since the system
+     * consumes all wake keys itself.
      */
+    @Deprecated
     public static final int FLAG_WOKE_HERE = 0x1;
-    
+
     /**
      * This mask is set if the key event was generated by a software keyboard.
      */
@@ -1837,13 +1851,34 @@
         }
     }
 
-    /** Whether key will, by default, trigger a click on the focused view.
+    /**
+     * Returns true if the key event should be treated as a confirming action.
+     * @return True for a confirmation key, such as {@link #KEYCODE_DPAD_CENTER},
+     * {@link #KEYCODE_ENTER}, or {@link #KEYCODE_BUTTON_A}.
      * @hide
      */
-    public static final boolean isConfirmKey(int keyCode) {
-        switch (keyCode) {
+    public final boolean isConfirmKey() {
+        switch (mKeyCode) {
             case KeyEvent.KEYCODE_DPAD_CENTER:
             case KeyEvent.KEYCODE_ENTER:
+            case KeyEvent.KEYCODE_BUTTON_A:
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    /**
+     * Returns true if the key event should be treated as a cancelling action.
+     * @return True for a cancellation key, such as {@link #KEYCODE_ESCAPE},
+     * {@link #KEYCODE_BACK}, or {@link #KEYCODE_BUTTON_B}.
+     * @hide
+     */
+    public final boolean isCancelKey() {
+        switch (mKeyCode) {
+            case KeyEvent.KEYCODE_BUTTON_B:
+            case KeyEvent.KEYCODE_ESCAPE:
+            case KeyEvent.KEYCODE_BACK:
                 return true;
             default:
                 return false;
diff --git a/core/java/android/view/MenuInflater.java b/core/java/android/view/MenuInflater.java
index a7ee12b..71296fa 100644
--- a/core/java/android/view/MenuInflater.java
+++ b/core/java/android/view/MenuInflater.java
@@ -161,6 +161,7 @@
                     } else if (tagName.equals(XML_MENU)) {
                         // A menu start tag denotes a submenu for an item
                         SubMenu subMenu = menuState.addSubMenuItem();
+                        registerMenu(subMenu, attrs);
 
                         // Parse the submenu into returned SubMenu
                         parseMenu(parser, attrs, subMenu);
@@ -183,9 +184,9 @@
                         if (!menuState.hasAddedItem()) {
                             if (menuState.itemActionProvider != null &&
                                     menuState.itemActionProvider.hasSubMenu()) {
-                                menuState.addSubMenuItem();
+                                registerMenu(menuState.addSubMenuItem(), attrs);
                             } else {
-                                menuState.addItem();
+                                registerMenu(menuState.addItem(), attrs);
                             }
                         }
                     } else if (tagName.equals(XML_MENU)) {
@@ -200,7 +201,30 @@
             eventType = parser.next();
         }
     }
-    
+
+    /**
+     * The method is a hook for layoutlib to do its magic.
+     * Nothing is needed outside of LayoutLib. However, it should not be deleted because it
+     * appears to do nothing.
+     */
+    private void registerMenu(@SuppressWarnings("unused") MenuItem item,
+            @SuppressWarnings("unused") AttributeSet set) {
+    }
+
+    /**
+     * The method is a hook for layoutlib to do its magic.
+     * Nothing is needed outside of LayoutLib. However, it should not be deleted because it
+     * appears to do nothing.
+     */
+    private void registerMenu(@SuppressWarnings("unused") SubMenu subMenu,
+            @SuppressWarnings("unused") AttributeSet set) {
+    }
+
+    // Needed by layoutlib.
+    /*package*/ Context getContext() {
+        return mContext;
+    }
+
     private static class InflatedOnMenuItemClickListener
             implements MenuItem.OnMenuItemClickListener {
         private static final Class<?>[] PARAM_TYPES = new Class[] { MenuItem.class };
@@ -446,9 +470,11 @@
             }
         }
 
-        public void addItem() {
+        public MenuItem addItem() {
             itemAdded = true;
-            setItem(menu.add(groupId, itemId, itemCategoryOrder, itemTitle));
+            MenuItem item = menu.add(groupId, itemId, itemCategoryOrder, itemTitle);
+            setItem(item);
+            return item;
         }
         
         public SubMenu addSubMenuItem() {
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index ddce3ce..6378ffd 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -3372,11 +3372,11 @@
                         throw new IllegalArgumentException("Axis out of range.");
                     }
                     final long bits = mPackedAxisBits;
-                    final long axisBit = 1L << axis;
+                    final long axisBit = 0x8000000000000000L >>> axis;
                     if ((bits & axisBit) == 0) {
                         return 0;
                     }
-                    final int index = Long.bitCount(bits & (axisBit - 1L));
+                    final int index = Long.bitCount(bits & ~(0xFFFFFFFFFFFFFFFFL >>> axis));
                     return mPackedAxisValues[index];
                 }
             }
@@ -3425,8 +3425,8 @@
                         throw new IllegalArgumentException("Axis out of range.");
                     }
                     final long bits = mPackedAxisBits;
-                    final long axisBit = 1L << axis;
-                    final int index = Long.bitCount(bits & (axisBit - 1L));
+                    final long axisBit = 0x8000000000000000L >>> axis;
+                    final int index = Long.bitCount(bits & ~(0xFFFFFFFFFFFFFFFFL >>> axis));
                     float[] values = mPackedAxisValues;
                     if ((bits & axisBit) == 0) {
                         if (values == null) {
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 62afa60..eea5884 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -79,9 +79,6 @@
     private final String mName;
     long mNativeObject; // package visibility only for Surface.java access
 
-    private static final boolean HEADLESS = "1".equals(
-        SystemProperties.get("ro.config.headless", "0"));
-
     /* flags used in constructor (keep in sync with ISurfaceComposerClient.h) */
 
     /**
@@ -106,18 +103,18 @@
      * surfaces are pre-multiplied, which means that each color component is
      * already multiplied by its alpha value. In this case the blending
      * equation used is:
-     *
-     *    DEST = SRC + DEST * (1-SRC_ALPHA)
-     *
+     * <p>
+     *    <code>DEST = SRC + DEST * (1-SRC_ALPHA)</code>
+     * <p>
      * By contrast, non pre-multiplied surfaces use the following equation:
-     *
-     *    DEST = SRC * SRC_ALPHA * DEST * (1-SRC_ALPHA)
-     *
+     * <p>
+     *    <code>DEST = SRC * SRC_ALPHA * DEST * (1-SRC_ALPHA)</code>
+     * <p>
      * pre-multiplied surfaces must always be used if transparent pixels are
      * composited on top of each-other into the surface. A pre-multiplied
      * surface can never lower the value of the alpha component of a given
      * pixel.
-     *
+     * <p>
      * In some rare situations, a non pre-multiplied surface is preferable.
      *
      */
@@ -128,7 +125,17 @@
      * even if its pixel format is set to translucent. This can be useful if an
      * application needs full RGBA 8888 support for instance but will
      * still draw every pixel opaque.
-     *
+     * <p>
+     * This flag is ignored if setAlpha() is used to make the surface non-opaque.
+     * Combined effects are (assuming a buffer format with an alpha channel):
+     * <ul>
+     * <li>OPAQUE + alpha(1.0) == opaque composition
+     * <li>OPAQUE + alpha(0.x) == blended composition
+     * <li>!OPAQUE + alpha(1.0) == blended composition
+     * <li>!OPAQUE + alpha(0.x) == blended composition
+     * </ul>
+     * If the underlying buffer lacks an alpha channel, the OPAQUE flag is effectively
+     * set automatically.
      */
     public static final int OPAQUE = 0x00000400;
 
@@ -169,9 +176,16 @@
     /**
      * Surface flag: Hide the surface.
      * Equivalent to calling hide().
+     * Updates the value set during Surface creation (see {@link #HIDDEN}).
      */
     public static final int SURFACE_HIDDEN = 0x01;
 
+    /**
+     * Surface flag: composite without blending when possible.
+     * Updates the value set during Surface creation (see {@link #OPAQUE}).
+     */
+    public static final int SURFACE_OPAQUE = 0x02;
+
 
     /* built-in physical display ids (keep in sync with ISurfaceComposer.h)
      * these are different from the logical display ids used elsewhere in the framework */
@@ -192,14 +206,14 @@
 
     /**
      * Create a surface with a name.
-     *
+     * <p>
      * The surface creation flags specify what kind of surface to create and
      * certain options such as whether the surface can be assumed to be opaque
      * and whether it should be initially hidden.  Surfaces should always be
      * created with the {@link #HIDDEN} flag set to ensure that they are not
      * made visible prematurely before all of the surface's properties have been
      * configured.
-     *
+     * <p>
      * Good practice is to first create the surface with the {@link #HIDDEN} flag
      * specified, open a transaction, set the surface layer, layer stack, alpha,
      * and position, call {@link #show} if appropriate, and close the transaction.
@@ -232,8 +246,6 @@
                     new Throwable());
         }
 
-        checkHeadless();
-
         mName = name;
         mNativeObject = nativeCreate(session, name, w, h, format, flags);
         if (mNativeObject == 0) {
@@ -344,6 +356,10 @@
         nativeSetTransparentRegionHint(mNativeObject, region);
     }
 
+    /**
+     * Sets an alpha value for the entire Surface.  This value is combined with the
+     * per-pixel alpha.  It may be used with opaque Surfaces.
+     */
     public void setAlpha(float alpha) {
         checkNotReleased();
         nativeSetAlpha(mNativeObject, alpha);
@@ -354,6 +370,13 @@
         nativeSetMatrix(mNativeObject, dsdx, dtdx, dsdy, dtdy);
     }
 
+    /**
+     * Sets and clears flags, such as {@link #SURFACE_HIDDEN}.  The new value will be:
+     * <p>
+     *   <code>newFlags = (oldFlags & ~mask) | (flags & mask)</code>
+     * <p>
+     * Note this does not take the same set of flags as the constructor.
+     */
     public void setFlags(int flags, int mask) {
         checkNotReleased();
         nativeSetFlags(mNativeObject, flags, mask);
@@ -374,6 +397,19 @@
         nativeSetLayerStack(mNativeObject, layerStack);
     }
 
+    /**
+     * Sets the opacity of the surface.  Setting the flag is equivalent to creating the
+     * Surface with the {@link #OPAQUE} flag.
+     */
+    public void setOpaque(boolean isOpaque) {
+        checkNotReleased();
+        if (isOpaque) {
+            nativeSetFlags(mNativeObject, SURFACE_OPAQUE, SURFACE_OPAQUE);
+        } else {
+            nativeSetFlags(mNativeObject, 0, SURFACE_OPAQUE);
+        }
+    }
+
     /*
      * set display parameters.
      * needs to be inside open/closeTransaction block
@@ -619,10 +655,4 @@
         }
         nativeScreenshot(display, consumer, width, height, minLayer, maxLayer, allLayers);
     }
-
-    private static void checkHeadless() {
-        if (HEADLESS) {
-            throw new UnsupportedOperationException("Device is headless");
-        }
-    }
 }
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index ef60755..872cbe7 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -2269,6 +2269,16 @@
     static final int PFLAG3_CALLED_SUPER = 0x10;
 
 
+    /**
+     * Flag indicating that we're in the process of applying window insets.
+     */
+    static final int PFLAG3_APPLYING_INSETS = 0x40;
+
+    /**
+     * Flag indicating that we're in the process of fitting system windows using the old method.
+     */
+    static final int PFLAG3_FITTING_SYSTEM_WINDOWS = 0x80;
+
     /* End of masks for mPrivateFlags3 */
 
     static final int DRAG_MASK = PFLAG2_DRAG_CAN_ACCEPT | PFLAG2_DRAG_HOVERED;
@@ -3178,6 +3188,8 @@
         private OnDragListener mOnDragListener;
 
         private OnSystemUiVisibilityChangeListener mOnSystemUiVisibilityChangeListener;
+
+        OnApplyWindowInsetsListener mOnApplyWindowInsetsListener;
     }
 
     ListenerInfo mListenerInfo;
@@ -5903,8 +5915,31 @@
      * @see #getFitsSystemWindows()
      * @see #setFitsSystemWindows(boolean) 
      * @see #setSystemUiVisibility(int)
+     *
+     * @deprecated As of API XX use {@link #dispatchApplyWindowInsets(WindowInsets)} to apply
+     * insets to views. Views should override {@link #onApplyWindowInsets(WindowInsets)} or use
+     * {@link #setOnApplyWindowInsetsListener(android.view.View.OnApplyWindowInsetsListener)}
+     * to implement handling their own insets.
      */
     protected boolean fitSystemWindows(Rect insets) {
+        if ((mPrivateFlags3 & PFLAG3_APPLYING_INSETS) == 0) {
+            // If we're not in the process of dispatching the newer apply insets call,
+            // that means we're not in the compatibility path. Dispatch into the newer
+            // apply insets path and take things from there.
+            try {
+                mPrivateFlags3 |= PFLAG3_FITTING_SYSTEM_WINDOWS;
+                return !dispatchApplyWindowInsets(new WindowInsets(insets)).hasInsets();
+            } finally {
+                mPrivateFlags3 &= PFLAG3_FITTING_SYSTEM_WINDOWS;
+            }
+        } else {
+            // We're being called from the newer apply insets path.
+            // Perform the standard fallback behavior.
+            return fitSystemWindowsInt(insets);
+        }
+    }
+
+    private boolean fitSystemWindowsInt(Rect insets) {
         if ((mViewFlags & FITS_SYSTEM_WINDOWS) == FITS_SYSTEM_WINDOWS) {
             mUserPaddingStart = UNDEFINED_PADDING;
             mUserPaddingEnd = UNDEFINED_PADDING;
@@ -5924,6 +5959,97 @@
     }
 
     /**
+     * Called when the view should apply {@link WindowInsets} according to its internal policy.
+     *
+     * <p>This method should be overridden by views that wish to apply a policy different from or
+     * in addition to the default behavior. Clients that wish to force a view subtree
+     * to apply insets should call {@link #dispatchApplyWindowInsets(WindowInsets)}.</p>
+     *
+     * <p>Clients may supply an {@link OnApplyWindowInsetsListener} to a view. If one is set
+     * it will be called during dispatch instead of this method. The listener may optionally
+     * call this method from its own implementation if it wishes to apply the view's default
+     * insets policy in addition to its own.</p>
+     *
+     * <p>Implementations of this method should either return the insets parameter unchanged
+     * or a new {@link WindowInsets} cloned from the supplied insets with any insets consumed
+     * that this view applied itself. This allows new inset types added in future platform
+     * versions to pass through existing implementations unchanged without being erroneously
+     * consumed.</p>
+     *
+     * <p>By default if a view's {@link #setFitsSystemWindows(boolean) fitsSystemWindows}
+     * property is set then the view will consume the system window insets and apply them
+     * as padding for the view.</p>
+     *
+     * @param insets Insets to apply
+     * @return The supplied insets with any applied insets consumed
+     */
+    public WindowInsets onApplyWindowInsets(WindowInsets insets) {
+        if ((mPrivateFlags3 & PFLAG3_FITTING_SYSTEM_WINDOWS) == 0) {
+            // We weren't called from within a direct call to fitSystemWindows,
+            // call into it as a fallback in case we're in a class that overrides it
+            // and has logic to perform.
+            if (fitSystemWindows(insets.getSystemWindowInsets())) {
+                return insets.consumeSystemWindowInsets();
+            }
+        } else {
+            // We were called from within a direct call to fitSystemWindows.
+            if (fitSystemWindowsInt(insets.getSystemWindowInsets())) {
+                return insets.consumeSystemWindowInsets();
+            }
+        }
+        return insets;
+    }
+
+    /**
+     * Set an {@link OnApplyWindowInsetsListener} to take over the policy for applying
+     * window insets to this view. The listener's
+     * {@link OnApplyWindowInsetsListener#onApplyWindowInsets(View, WindowInsets) onApplyWindowInsets}
+     * method will be called instead of the view's
+     * {@link #onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method.
+     *
+     * @param listener Listener to set
+     *
+     * @see #onApplyWindowInsets(WindowInsets)
+     */
+    public void setOnApplyWindowInsetsListener(OnApplyWindowInsetsListener listener) {
+        getListenerInfo().mOnApplyWindowInsetsListener = listener;
+    }
+
+    /**
+     * Request to apply the given window insets to this view or another view in its subtree.
+     *
+     * <p>This method should be called by clients wishing to apply insets corresponding to areas
+     * obscured by window decorations or overlays. This can include the status and navigation bars,
+     * action bars, input methods and more. New inset categories may be added in the future.
+     * The method returns the insets provided minus any that were applied by this view or its
+     * children.</p>
+     *
+     * <p>Clients wishing to provide custom behavior should override the
+     * {@link #onApplyWindowInsets(WindowInsets)} method or alternatively provide a
+     * {@link OnApplyWindowInsetsListener} via the
+     * {@link #setOnApplyWindowInsetsListener(View.OnApplyWindowInsetsListener) setOnApplyWindowInsetsListener}
+     * method.</p>
+     *
+     * <p>This method replaces the older {@link #fitSystemWindows(Rect) fitSystemWindows} method.
+     * </p>
+     *
+     * @param insets Insets to apply
+     * @return The provided insets minus the insets that were consumed
+     */
+    public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) {
+        try {
+            mPrivateFlags3 |= PFLAG3_APPLYING_INSETS;
+            if (mListenerInfo != null && mListenerInfo.mOnApplyWindowInsetsListener != null) {
+                return mListenerInfo.mOnApplyWindowInsetsListener.onApplyWindowInsets(this, insets);
+            } else {
+                return onApplyWindowInsets(insets);
+            }
+        } finally {
+            mPrivateFlags3 &= ~PFLAG3_APPLYING_INSETS;
+        }
+    }
+
+    /**
      * @hide Compute the insets that should be consumed by this view and the ones
      * that should propagate to those under it.
      */
@@ -5995,6 +6121,7 @@
 
     /**
      * Ask that a new dispatch of {@link #fitSystemWindows(Rect)} be performed.
+     * @deprecated Use {@link #requestApplyInsets()} for newer platform versions.
      */
     public void requestFitSystemWindows() {
         if (mParent != null) {
@@ -6003,6 +6130,13 @@
     }
 
     /**
+     * Ask that a new dispatch of {@link #onApplyWindowInsets(WindowInsets)} be performed.
+     */
+    public void requestApplyInsets() {
+        requestFitSystemWindows();
+    }
+
+    /**
      * For use by PhoneWindow to make its own system window fitting optional.
      * @hide
      */
@@ -8186,7 +8320,7 @@
     public boolean onKeyDown(int keyCode, KeyEvent event) {
         boolean result = false;
 
-        if (KeyEvent.isConfirmKey(keyCode)) {
+        if (event.isConfirmKey()) {
             if ((mViewFlags & ENABLED_MASK) == DISABLED) {
                 return true;
             }
@@ -8228,7 +8362,7 @@
      * @param event   The KeyEvent object that defines the button action.
      */
     public boolean onKeyUp(int keyCode, KeyEvent event) {
-        if (KeyEvent.isConfirmKey(keyCode)) {
+        if (event.isConfirmKey()) {
             if ((mViewFlags & ENABLED_MASK) == DISABLED) {
                 return true;
             }
@@ -9493,6 +9627,7 @@
                 // View was rejected last time it was drawn by its parent; this may have changed
                 invalidateParentIfNeeded();
             }
+            notifySubtreeAccessibilityStateChangedIfNeeded();
         }
     }
 
@@ -9544,6 +9679,7 @@
                 // View was rejected last time it was drawn by its parent; this may have changed
                 invalidateParentIfNeeded();
             }
+            notifySubtreeAccessibilityStateChangedIfNeeded();
         }
     }
 
@@ -9595,6 +9731,7 @@
                 // View was rejected last time it was drawn by its parent; this may have changed
                 invalidateParentIfNeeded();
             }
+            notifySubtreeAccessibilityStateChangedIfNeeded();
         }
     }
 
@@ -9638,6 +9775,7 @@
                 // View was rejected last time it was drawn by its parent; this may have changed
                 invalidateParentIfNeeded();
             }
+            notifySubtreeAccessibilityStateChangedIfNeeded();
         }
     }
 
@@ -9681,6 +9819,7 @@
                 // View was rejected last time it was drawn by its parent; this may have changed
                 invalidateParentIfNeeded();
             }
+            notifySubtreeAccessibilityStateChangedIfNeeded();
         }
     }
 
@@ -9866,6 +10005,8 @@
                 if (mDisplayList != null) {
                     mDisplayList.setAlpha(getFinalAlpha());
                 }
+                notifyViewAccessibilityStateChangedIfNeeded(
+                        AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
             }
         }
     }
@@ -10299,6 +10440,7 @@
                 // View was rejected last time it was drawn by its parent; this may have changed
                 invalidateParentIfNeeded();
             }
+            notifySubtreeAccessibilityStateChangedIfNeeded();
         }
     }
 
@@ -10340,6 +10482,7 @@
                 // View was rejected last time it was drawn by its parent; this may have changed
                 invalidateParentIfNeeded();
             }
+            notifySubtreeAccessibilityStateChangedIfNeeded();
         }
     }
 
@@ -10486,6 +10629,7 @@
                 }
                 invalidateParentIfNeeded();
             }
+            notifySubtreeAccessibilityStateChangedIfNeeded();
         }
     }
 
@@ -10534,6 +10678,7 @@
                 }
                 invalidateParentIfNeeded();
             }
+            notifySubtreeAccessibilityStateChangedIfNeeded();
         }
     }
 
@@ -16499,7 +16644,7 @@
             } else {
                 long value = mMeasureCache.valueAt(cacheIndex);
                 // Casting a long to int drops the high 32 bits, no mask needed
-                setMeasuredDimension((int) (value >> 32), (int) value);
+                setMeasuredDimensionRaw((int) (value >> 32), (int) value);
                 mPrivateFlags3 |= PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;
             }
 
@@ -16594,6 +16739,22 @@
             measuredWidth  += optical ? opticalWidth  : -opticalWidth;
             measuredHeight += optical ? opticalHeight : -opticalHeight;
         }
+        setMeasuredDimensionRaw(measuredWidth, measuredHeight);
+    }
+
+    /**
+     * Sets the measured dimension without extra processing for things like optical bounds.
+     * Useful for reapplying consistent values that have already been cooked with adjustments
+     * for optical bounds, etc. such as those from the measurement cache.
+     *
+     * @param measuredWidth The measured width of this view.  May be a complex
+     * bit mask as defined by {@link #MEASURED_SIZE_MASK} and
+     * {@link #MEASURED_STATE_TOO_SMALL}.
+     * @param measuredHeight The measured height of this view.  May be a complex
+     * bit mask as defined by {@link #MEASURED_SIZE_MASK} and
+     * {@link #MEASURED_STATE_TOO_SMALL}.
+     */
+    private void setMeasuredDimensionRaw(int measuredWidth, int measuredHeight) {
         mMeasuredWidth = measuredWidth;
         mMeasuredHeight = measuredHeight;
 
@@ -16824,8 +16985,8 @@
             // If the screen is off assume the animation start time is now instead of
             // the next frame we draw. Keeping the START_ON_FIRST_FRAME start time
             // would cause the animation to start when the screen turns back on
-            if (mAttachInfo != null && !mAttachInfo.mScreenOn &&
-                    animation.getStartTime() == Animation.START_ON_FIRST_FRAME) {
+            if (mAttachInfo != null && mAttachInfo.mDisplayState == Display.STATE_OFF
+                    && animation.getStartTime() == Animation.START_ON_FIRST_FRAME) {
                 animation.setStartTime(AnimationUtils.currentAnimationTimeMillis());
             }
             animation.reset();
@@ -18361,7 +18522,18 @@
         }
 
         static int adjust(int measureSpec, int delta) {
-            return makeMeasureSpec(getSize(measureSpec + delta), getMode(measureSpec));
+            final int mode = getMode(measureSpec);
+            if (mode == UNSPECIFIED) {
+                // No need to adjust size for UNSPECIFIED mode.
+                return makeMeasureSpec(0, UNSPECIFIED);
+            }
+            int size = getSize(measureSpec) + delta;
+            if (size < 0) {
+                Log.e(VIEW_LOG_TAG, "MeasureSpec.adjust: new size would be negative! (" + size +
+                        ") spec: " + toString(measureSpec) + " delta: " + delta);
+                size = 0;
+            }
+            return makeMeasureSpec(size, mode);
         }
 
         /**
@@ -18641,6 +18813,31 @@
         public void onViewDetachedFromWindow(View v);
     }
 
+    /**
+     * Listener for applying window insets on a view in a custom way.
+     *
+     * <p>Apps may choose to implement this interface if they want to apply custom policy
+     * to the way that window insets are treated for a view. If an OnApplyWindowInsetsListener
+     * is set, its
+     * {@link OnApplyWindowInsetsListener#onApplyWindowInsets(View, WindowInsets) onApplyWindowInsets}
+     * method will be called instead of the View's own
+     * {@link #onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method. The listener
+     * may optionally call the parameter View's <code>onApplyWindowInsets</code> method to apply
+     * the View's normal behavior as part of its own.</p>
+     */
+    public interface OnApplyWindowInsetsListener {
+        /**
+         * When {@link View#setOnApplyWindowInsetsListener(View.OnApplyWindowInsetsListener) set}
+         * on a View, this listener method will be called instead of the view's own
+         * {@link View#onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method.
+         *
+         * @param v The view applying window insets
+         * @param insets The insets to apply
+         * @return The insets supplied, minus any insets that were consumed
+         */
+        public WindowInsets onApplyWindowInsets(View v, WindowInsets insets);
+    }
+
     private final class UnsetPressedState implements Runnable {
         public void run() {
             setPressed(false);
@@ -18686,7 +18883,7 @@
      * A set of information given to a view when it is attached to its parent
      * window.
      */
-    static class AttachInfo {
+    final static class AttachInfo {
         interface Callbacks {
             void playSoundEffect(int effectId);
             boolean performHapticFeedback(int effectId, boolean always);
@@ -18752,7 +18949,14 @@
         boolean mHardwareAccelerationRequested;
         HardwareRenderer mHardwareRenderer;
 
-        boolean mScreenOn;
+        /**
+         * The state of the display to which the window is attached, as reported
+         * by {@link Display#getState()}.  Note that the display state constants
+         * declared by {@link Display} do not exactly line up with the screen state
+         * constants declared by {@link View} (there are more display states than
+         * screen states).
+         */
+        int mDisplayState = Display.STATE_UNKNOWN;
 
         /**
          * Scale factor used by the compatibility mode
diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index e67659c..ad64ca7 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -234,6 +234,7 @@
     private final int mOverscrollDistance;
     private final int mOverflingDistance;
     private final boolean mFadingMarqueeEnabled;
+    private final long mGlobalActionsKeyTimeout;
 
     private boolean sHasPermanentMenuKey;
     private boolean sHasPermanentMenuKeySet;
@@ -261,6 +262,7 @@
         mOverscrollDistance = OVERSCROLL_DISTANCE;
         mOverflingDistance = OVERFLING_DISTANCE;
         mFadingMarqueeEnabled = true;
+        mGlobalActionsKeyTimeout = GLOBAL_ACTIONS_KEY_TIMEOUT;
     }
 
     /**
@@ -287,8 +289,6 @@
 
         mEdgeSlop = (int) (sizeAndDensity * EDGE_SLOP + 0.5f);
         mFadingEdgeLength = (int) (sizeAndDensity * FADING_EDGE_LENGTH + 0.5f);
-        mMinimumFlingVelocity = (int) (density * MINIMUM_FLING_VELOCITY + 0.5f);
-        mMaximumFlingVelocity = (int) (density * MAXIMUM_FLING_VELOCITY + 0.5f);
         mScrollbarSize = (int) (density * SCROLL_BAR_SIZE + 0.5f);
         mDoubleTapSlop = (int) (sizeAndDensity * DOUBLE_TAP_SLOP + 0.5f);
         mWindowTouchSlop = (int) (sizeAndDensity * WINDOW_TOUCH_SLOP + 0.5f);
@@ -339,6 +339,13 @@
         mPagingTouchSlop = mTouchSlop * 2;
 
         mDoubleTapTouchSlop = mTouchSlop;
+
+        mMinimumFlingVelocity = res.getDimensionPixelSize(
+                com.android.internal.R.dimen.config_viewMinFlingVelocity);
+        mMaximumFlingVelocity = res.getDimensionPixelSize(
+                com.android.internal.R.dimen.config_viewMaxFlingVelocity);
+        mGlobalActionsKeyTimeout = res.getInteger(
+                com.android.internal.R.integer.config_globalActionsKeyTimeout);
     }
 
     /**
@@ -695,12 +702,26 @@
      *
      * @return how long a user needs to press the relevant key to bring up
      *   the global actions dialog.
+     * @deprecated This timeout should not be used by applications
      */
+    @Deprecated
     public static long getGlobalActionKeyTimeout() {
         return GLOBAL_ACTIONS_KEY_TIMEOUT;
     }
 
     /**
+     * The amount of time a user needs to press the relevant key to bring up
+     * the global actions dialog.
+     *
+     * @return how long a user needs to press the relevant key to bring up
+     *   the global actions dialog.
+     * @hide
+     */
+    public long getDeviceGlobalActionKeyTimeout() {
+        return mGlobalActionsKeyTimeout;
+    }
+
+    /**
      * The amount of friction applied to scrolls and flings.
      *
      * @return A scalar dimensionless value representing the coefficient of
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 9414237..dda5a60 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -463,13 +463,13 @@
     public ViewGroup(Context context, AttributeSet attrs) {
         super(context, attrs);
         initViewGroup();
-        initFromAttributes(context, attrs);
+        initFromAttributes(context, attrs, 0);
     }
 
     public ViewGroup(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
         initViewGroup();
-        initFromAttributes(context, attrs);
+        initFromAttributes(context, attrs, defStyle);
     }
 
     private boolean debugDraw() {
@@ -499,9 +499,8 @@
         mPersistentDrawingCache = PERSISTENT_SCROLLING_CACHE;
     }
 
-    private void initFromAttributes(Context context, AttributeSet attrs) {
-        TypedArray a = context.obtainStyledAttributes(attrs,
-                R.styleable.ViewGroup);
+    private void initFromAttributes(Context context, AttributeSet attrs, int defStyle) {
+        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ViewGroup, defStyle, 0);
 
         final int N = a.getIndexCount();
         for (int i = 0; i < N; i++) {
@@ -4574,6 +4573,7 @@
         if (invalidate) {
             invalidateViewProperty(false, false);
         }
+        notifySubtreeAccessibilityStateChangedIfNeeded();
     }
 
     /**
@@ -5430,21 +5430,19 @@
         }
     }
 
-
     @Override
-    protected boolean fitSystemWindows(Rect insets) {
-        boolean done = super.fitSystemWindows(insets);
-        if (!done) {
-            final int count = mChildrenCount;
-            final View[] children = mChildren;
+    public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) {
+        insets = super.dispatchApplyWindowInsets(insets);
+        if (insets.hasInsets()) {
+            final int count = getChildCount();
             for (int i = 0; i < count; i++) {
-                done = children[i].fitSystemWindows(insets);
-                if (done) {
+                insets = getChildAt(i).dispatchApplyWindowInsets(insets);
+                if (!insets.hasInsets()) {
                     break;
                 }
             }
         }
-        return done;
+        return insets;
     }
 
     /**
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 5b2a452..1cb0473 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -36,6 +36,8 @@
 import android.graphics.Rect;
 import android.graphics.Region;
 import android.graphics.drawable.Drawable;
+import android.hardware.display.DisplayManager;
+import android.hardware.display.DisplayManager.DisplayListener;
 import android.media.AudioManager;
 import android.os.Binder;
 import android.os.Bundle;
@@ -134,6 +136,7 @@
     final Context mContext;
     final IWindowSession mWindowSession;
     final Display mDisplay;
+    final DisplayManager mDisplayManager;
     final String mBasePackageName;
 
     final int[] mTmpLocation = new int[2];
@@ -368,9 +371,7 @@
         mNoncompatDensity = context.getResources().getDisplayMetrics().noncompatDensityDpi;
         mFallbackEventHandler = PolicyManager.makeNewFallbackEventHandler(context);
         mChoreographer = Choreographer.getInstance();
-
-        PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
-        mAttachInfo.mScreenOn = powerManager.isScreenOn();
+        mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
         loadSystemProperties();
     }
 
@@ -425,6 +426,10 @@
         synchronized (this) {
             if (mView == null) {
                 mView = view;
+
+                mAttachInfo.mDisplayState = mDisplay.getState();
+                mDisplayManager.registerDisplayListener(mDisplayListener, mHandler);
+
                 mViewLayoutDirectionInitial = mView.getRawLayoutDirection();
                 mFallbackEventHandler.setView(view);
                 mWindowAttributes.copyFrom(attrs);
@@ -794,18 +799,43 @@
         scheduleTraversals();
     }
 
-    void handleScreenStateChange(boolean on) {
-        if (on != mAttachInfo.mScreenOn) {
-            mAttachInfo.mScreenOn = on;
-            if (mView != null) {
-                mView.dispatchScreenStateChanged(on ? View.SCREEN_STATE_ON : View.SCREEN_STATE_OFF);
-            }
-            if (on) {
-                mFullRedrawNeeded = true;
-                scheduleTraversals();
+    private final DisplayListener mDisplayListener = new DisplayListener() {
+        @Override
+        public void onDisplayChanged(int displayId) {
+            if (mView != null && mDisplay.getDisplayId() == displayId) {
+                final int oldDisplayState = mAttachInfo.mDisplayState;
+                final int newDisplayState = mDisplay.getState();
+                if (oldDisplayState != newDisplayState) {
+                    mAttachInfo.mDisplayState = newDisplayState;
+                    if (oldDisplayState != Display.STATE_UNKNOWN) {
+                        final int oldScreenState = toViewScreenState(oldDisplayState);
+                        final int newScreenState = toViewScreenState(newDisplayState);
+                        if (oldScreenState != newScreenState) {
+                            mView.dispatchScreenStateChanged(newScreenState);
+                        }
+                        if (oldDisplayState == Display.STATE_OFF) {
+                            // Draw was suppressed so we need to for it to happen here.
+                            mFullRedrawNeeded = true;
+                            scheduleTraversals();
+                        }
+                    }
+                }
             }
         }
-    }
+
+        @Override
+        public void onDisplayRemoved(int displayId) {
+        }
+
+        @Override
+        public void onDisplayAdded(int displayId) {
+        }
+
+        private int toViewScreenState(int displayState) {
+            return displayState == Display.STATE_OFF ?
+                    View.SCREEN_STATE_OFF : View.SCREEN_STATE_ON;
+        }
+    };
 
     @Override
     public void requestFitSystemWindows() {
@@ -1121,6 +1151,19 @@
         return windowSizeMayChange;
     }
 
+    void dispatchApplyInsets(View host) {
+        mFitSystemWindowsInsets.set(mAttachInfo.mContentInsets);
+        boolean isRound = false;
+        if ((mWindowAttributes.flags & WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN) != 0
+                && mDisplay.getDisplayId() == 0) {
+            // we're fullscreen and not hosted in an ActivityView
+            isRound = mContext.getResources().getBoolean(
+                    com.android.internal.R.bool.config_windowIsRound);
+        }
+        host.dispatchApplyWindowInsets(new WindowInsets(
+                mFitSystemWindowsInsets, isRound));
+    }
+
     private void performTraversals() {
         // cache mView since it is used so much below...
         final View host = mView;
@@ -1212,8 +1255,7 @@
             }
             host.dispatchAttachedToWindow(attachInfo, 0);
             attachInfo.mTreeObserver.dispatchOnWindowAttachedChange(true);
-            mFitSystemWindowsInsets.set(mAttachInfo.mContentInsets);
-            host.fitSystemWindows(mFitSystemWindowsInsets);
+            dispatchApplyInsets(host);
             //Log.i(TAG, "Screen on initialized: " + attachInfo.mKeepScreenOn);
 
         } else {
@@ -1338,9 +1380,8 @@
 
         if (mFitSystemWindowsRequested) {
             mFitSystemWindowsRequested = false;
-            mFitSystemWindowsInsets.set(mAttachInfo.mContentInsets);
             mLastOverscanRequested = mAttachInfo.mOverscanRequested;
-            host.fitSystemWindows(mFitSystemWindowsInsets);
+            dispatchApplyInsets(host);
             if (mLayoutRequested) {
                 // Short-circuit catching a new layout request here, so
                 // we don't need to go through two layout passes when things
@@ -1519,8 +1560,7 @@
                     mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
                     mLastOverscanRequested = mAttachInfo.mOverscanRequested;
                     mFitSystemWindowsRequested = false;
-                    mFitSystemWindowsInsets.set(mAttachInfo.mContentInsets);
-                    host.fitSystemWindows(mFitSystemWindowsInsets);
+                    dispatchApplyInsets(host);
                 }
                 if (visibleInsetsChanged) {
                     mAttachInfo.mVisibleInsets.set(mPendingVisibleInsets);
@@ -2236,7 +2276,7 @@
     }
 
     private void performDraw() {
-        if (!mAttachInfo.mScreenOn && !mReportNextDraw) {
+        if (mAttachInfo.mDisplayState == Display.STATE_OFF && !mReportNextDraw) {
             return;
         }
 
@@ -2872,6 +2912,8 @@
             mInputChannel = null;
         }
 
+        mDisplayManager.unregisterDisplayListener(mDisplayListener);
+
         unscheduleTraversals();
     }
 
@@ -2951,7 +2993,6 @@
     private final static int MSG_DISPATCH_SYSTEM_UI_VISIBILITY = 17;
     private final static int MSG_UPDATE_CONFIGURATION = 18;
     private final static int MSG_PROCESS_INPUT_EVENTS = 19;
-    private final static int MSG_DISPATCH_SCREEN_STATE = 20;
     private final static int MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST = 21;
     private final static int MSG_DISPATCH_DONE_ANIMATING = 22;
     private final static int MSG_INVALIDATE_WORLD = 23;
@@ -2998,8 +3039,6 @@
                     return "MSG_UPDATE_CONFIGURATION";
                 case MSG_PROCESS_INPUT_EVENTS:
                     return "MSG_PROCESS_INPUT_EVENTS";
-                case MSG_DISPATCH_SCREEN_STATE:
-                    return "MSG_DISPATCH_SCREEN_STATE";
                 case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST:
                     return "MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST";
                 case MSG_DISPATCH_DONE_ANIMATING:
@@ -3215,11 +3254,6 @@
                 }
                 updateConfiguration(config, false);
             } break;
-            case MSG_DISPATCH_SCREEN_STATE: {
-                if (mView != null) {
-                    handleScreenStateChange(msg.arg1 == 1);
-                }
-            } break;
             case MSG_CLEAR_ACCESSIBILITY_FOCUS_HOST: {
                 setAccessibilityFocus(null, null);
             } break;
@@ -3692,7 +3726,8 @@
                     if (result == InputMethodManager.DISPATCH_HANDLED) {
                         return FINISH_HANDLED;
                     } else if (result == InputMethodManager.DISPATCH_NOT_HANDLED) {
-                        return FINISH_NOT_HANDLED;
+                        // The IME could not handle it, so skip along to the next InputStage
+                        return FORWARD;
                     } else {
                         return DEFER; // callback will be invoked later
                     }
@@ -4319,6 +4354,7 @@
      * Creates dpad events from unhandled joystick movements.
      */
     final class SyntheticJoystickHandler extends Handler {
+        private final static String TAG = "SyntheticJoystickHandler";
         private final static int MSG_ENQUEUE_X_AXIS_KEY_REPEAT = 1;
         private final static int MSG_ENQUEUE_Y_AXIS_KEY_REPEAT = 2;
 
@@ -4351,10 +4387,21 @@
         }
 
         public void process(MotionEvent event) {
-            update(event, true);
+            switch(event.getActionMasked()) {
+            case MotionEvent.ACTION_CANCEL:
+                cancel(event);
+                break;
+            case MotionEvent.ACTION_MOVE:
+                update(event, true);
+                break;
+            default:
+                Log.w(TAG, "Unexpected action: " + event.getActionMasked());
+            }
         }
 
-        public void cancel(MotionEvent event) {
+        private void cancel(MotionEvent event) {
+            removeMessages(MSG_ENQUEUE_X_AXIS_KEY_REPEAT);
+            removeMessages(MSG_ENQUEUE_Y_AXIS_KEY_REPEAT);
             update(event, false);
         }
 
@@ -5793,12 +5840,6 @@
         mHandler.sendMessage(msg);
     }
 
-    public void dispatchScreenStateChange(boolean on) {
-        Message msg = mHandler.obtainMessage(MSG_DISPATCH_SCREEN_STATE);
-        msg.arg1 = on ? 1 : 0;
-        mHandler.sendMessage(msg);
-    }
-
     public void dispatchGetNewSurface() {
         Message msg = mHandler.obtainMessage(MSG_DISPATCH_GET_NEW_SURFACE);
         mHandler.sendMessage(msg);
@@ -6137,14 +6178,6 @@
         }
 
         @Override
-        public void dispatchScreenState(boolean on) {
-            final ViewRootImpl viewAncestor = mViewAncestor.get();
-            if (viewAncestor != null) {
-                viewAncestor.dispatchScreenStateChange(on);
-            }
-        }
-
-        @Override
         public void dispatchGetNewSurface() {
             final ViewRootImpl viewAncestor = mViewAncestor.get();
             if (viewAncestor != null) {
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index b3a0699..59d8fbc 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -91,10 +91,15 @@
     public static final int FEATURE_ACTION_MODE_OVERLAY = 10;
 
     /**
+     * Flag for requesting a decoration-free window that is dismissed by swiping from the left.
+     */
+    public static final int FEATURE_SWIPE_TO_DISMISS = 11;
+
+    /**
      * Max value used as a feature ID
      * @hide
      */
-    public static final int FEATURE_MAX = FEATURE_ACTION_MODE_OVERLAY;
+    public static final int FEATURE_MAX = FEATURE_SWIPE_TO_DISMISS;
 
     /** Flag for setting the progress bar's visibility to VISIBLE */
     public static final int PROGRESS_VISIBILITY_ON = -1;
@@ -129,6 +134,7 @@
     
     private TypedArray mWindowStyle;
     private Callback mCallback;
+    private OnWindowDismissedCallback mOnWindowDismissedCallback;
     private WindowManager mWindowManager;
     private IBinder mAppToken;
     private String mAppName;
@@ -387,6 +393,15 @@
         public void onActionModeFinished(ActionMode mode);
     }
 
+    /** @hide */
+    public interface OnWindowDismissedCallback {
+        /**
+         * Called when a window is dismissed. This informs the callback that the
+         * window is gone, and it should finish itself.
+         */
+        public void onWindowDismissed();
+    }
+
     public Window(Context context) {
         mContext = context;
     }
@@ -560,6 +575,18 @@
         return mCallback;
     }
 
+    /** @hide */
+    public final void setOnWindowDismissedCallback(OnWindowDismissedCallback dcb) {
+        mOnWindowDismissedCallback = dcb;
+    }
+
+    /** @hide */
+    public final void dispatchOnWindowDismissed() {
+        if (mOnWindowDismissedCallback != null) {
+            mOnWindowDismissedCallback.onWindowDismissed();
+        }
+    }
+
     /**
      * Take ownership of this window's surface.  The window's view hierarchy
      * will no longer draw into the surface, though it will otherwise continue
diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java
new file mode 100644
index 0000000..294f472
--- /dev/null
+++ b/core/java/android/view/WindowInsets.java
@@ -0,0 +1,344 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package android.view;
+
+import android.graphics.Rect;
+
+/**
+ * Describes a set of insets for window content.
+ *
+ * <p>WindowInsets are immutable and may be expanded to include more inset types in the future.
+ * To adjust insets, use one of the supplied clone methods to obtain a new WindowInsets instance
+ * with the adjusted properties.</p>
+ *
+ * @see View.OnApplyWindowInsetsListener
+ * @see View#onApplyWindowInsets(WindowInsets)
+ */
+public final class WindowInsets {
+    private Rect mSystemWindowInsets;
+    private Rect mWindowDecorInsets;
+    private Rect mTempRect;
+    private boolean mIsRound;
+
+    private static final Rect EMPTY_RECT = new Rect(0, 0, 0, 0);
+
+    /**
+     * Since new insets may be added in the future that existing apps couldn't
+     * know about, this fully empty constant shouldn't be made available to apps
+     * since it would allow them to inadvertently consume unknown insets by returning it.
+     * @hide
+     */
+    public static final WindowInsets EMPTY = new WindowInsets(EMPTY_RECT, EMPTY_RECT);
+
+    /** @hide */
+    public WindowInsets(Rect systemWindowInsets, Rect windowDecorInsets) {
+        this(systemWindowInsets, windowDecorInsets, false);
+    }
+
+    /** @hide */
+    public WindowInsets(Rect systemWindowInsets, boolean isRound) {
+        this(systemWindowInsets, EMPTY_RECT, isRound);
+    }
+
+    /** @hide */
+    public WindowInsets(Rect systemWindowInsets, Rect windowDecorInsets, boolean isRound) {
+        mSystemWindowInsets = systemWindowInsets;
+        mWindowDecorInsets = windowDecorInsets;
+        mIsRound = isRound;
+    }
+
+    /**
+     * Construct a new WindowInsets, copying all values from a source WindowInsets.
+     *
+     * @param src Source to copy insets from
+     */
+    public WindowInsets(WindowInsets src) {
+        mSystemWindowInsets = src.mSystemWindowInsets;
+        mWindowDecorInsets = src.mWindowDecorInsets;
+        mIsRound = src.mIsRound;
+    }
+
+    /** @hide */
+    public WindowInsets(Rect systemWindowInsets) {
+        this(systemWindowInsets, EMPTY_RECT);
+    }
+
+    /**
+     * Used to provide a safe copy of the system window insets to pass through
+     * to the existing fitSystemWindows method and other similar internals.
+     * @hide
+     */
+    public Rect getSystemWindowInsets() {
+        if (mTempRect == null) {
+            mTempRect = new Rect();
+        }
+        mTempRect.set(mSystemWindowInsets);
+        return mTempRect;
+    }
+
+    /**
+     * Returns the left system window inset in pixels.
+     *
+     * <p>The system window inset represents the area of a full-screen window that is
+     * partially or fully obscured by the status bar, navigation bar, IME or other system windows.
+     * </p>
+     *
+     * @return The left system window inset
+     */
+    public int getSystemWindowInsetLeft() {
+        return mSystemWindowInsets.left;
+    }
+
+    /**
+     * Returns the top system window inset in pixels.
+     *
+     * <p>The system window inset represents the area of a full-screen window that is
+     * partially or fully obscured by the status bar, navigation bar, IME or other system windows.
+     * </p>
+     *
+     * @return The top system window inset
+     */
+    public int getSystemWindowInsetTop() {
+        return mSystemWindowInsets.top;
+    }
+
+    /**
+     * Returns the right system window inset in pixels.
+     *
+     * <p>The system window inset represents the area of a full-screen window that is
+     * partially or fully obscured by the status bar, navigation bar, IME or other system windows.
+     * </p>
+     *
+     * @return The right system window inset
+     */
+    public int getSystemWindowInsetRight() {
+        return mSystemWindowInsets.right;
+    }
+
+    /**
+     * Returns the bottom system window inset in pixels.
+     *
+     * <p>The system window inset represents the area of a full-screen window that is
+     * partially or fully obscured by the status bar, navigation bar, IME or other system windows.
+     * </p>
+     *
+     * @return The bottom system window inset
+     */
+    public int getSystemWindowInsetBottom() {
+        return mSystemWindowInsets.bottom;
+    }
+
+    /**
+     * Returns the left window decor inset in pixels.
+     *
+     * <p>The window decor inset represents the area of the window content area that is
+     * partially or fully obscured by decorations within the window provided by the framework.
+     * This can include action bars, title bars, toolbars, etc.</p>
+     *
+     * @return The left window decor inset
+     * @hide pending API
+     */
+    public int getWindowDecorInsetLeft() {
+        return mWindowDecorInsets.left;
+    }
+
+    /**
+     * Returns the top window decor inset in pixels.
+     *
+     * <p>The window decor inset represents the area of the window content area that is
+     * partially or fully obscured by decorations within the window provided by the framework.
+     * This can include action bars, title bars, toolbars, etc.</p>
+     *
+     * @return The top window decor inset
+     * @hide pending API
+     */
+    public int getWindowDecorInsetTop() {
+        return mWindowDecorInsets.top;
+    }
+
+    /**
+     * Returns the right window decor inset in pixels.
+     *
+     * <p>The window decor inset represents the area of the window content area that is
+     * partially or fully obscured by decorations within the window provided by the framework.
+     * This can include action bars, title bars, toolbars, etc.</p>
+     *
+     * @return The right window decor inset
+     * @hide pending API
+     */
+    public int getWindowDecorInsetRight() {
+        return mWindowDecorInsets.right;
+    }
+
+    /**
+     * Returns the bottom window decor inset in pixels.
+     *
+     * <p>The window decor inset represents the area of the window content area that is
+     * partially or fully obscured by decorations within the window provided by the framework.
+     * This can include action bars, title bars, toolbars, etc.</p>
+     *
+     * @return The bottom window decor inset
+     * @hide pending API
+     */
+    public int getWindowDecorInsetBottom() {
+        return mWindowDecorInsets.bottom;
+    }
+
+    /**
+     * Returns true if this WindowInsets has nonzero system window insets.
+     *
+     * <p>The system window inset represents the area of a full-screen window that is
+     * partially or fully obscured by the status bar, navigation bar, IME or other system windows.
+     * </p>
+     *
+     * @return true if any of the system window inset values are nonzero
+     */
+    public boolean hasSystemWindowInsets() {
+        return mSystemWindowInsets.left != 0 || mSystemWindowInsets.top != 0 ||
+                mSystemWindowInsets.right != 0 || mSystemWindowInsets.bottom != 0;
+    }
+
+    /**
+     * Returns true if this WindowInsets has nonzero window decor insets.
+     *
+     * <p>The window decor inset represents the area of the window content area that is
+     * partially or fully obscured by decorations within the window provided by the framework.
+     * This can include action bars, title bars, toolbars, etc.</p>
+     *
+     * @return true if any of the window decor inset values are nonzero
+     * @hide pending API
+     */
+    public boolean hasWindowDecorInsets() {
+        return mWindowDecorInsets.left != 0 || mWindowDecorInsets.top != 0 ||
+                mWindowDecorInsets.right != 0 || mWindowDecorInsets.bottom != 0;
+    }
+
+    /**
+     * Returns true if this WindowInsets has any nonzero insets.
+     *
+     * @return true if any inset values are nonzero
+     */
+    public boolean hasInsets() {
+        return hasSystemWindowInsets() || hasWindowDecorInsets();
+    }
+
+    /**
+     * Returns true if the associated window has a round shape.
+     *
+     * <p>A round window's left, top, right and bottom edges reach all the way to the
+     * associated edges of the window but the corners may not be visible. Views responding
+     * to round insets should take care to not lay out critical elements within the corners
+     * where they may not be accessible.</p>
+     *
+     * @return True if the window is round
+     */
+    public boolean isRound() {
+        return mIsRound;
+    }
+
+    /**
+     * Returns a copy of this WindowInsets with the system window insets fully consumed.
+     *
+     * @return A modified copy of this WindowInsets
+     */
+    public WindowInsets consumeSystemWindowInsets() {
+        final WindowInsets result = new WindowInsets(this);
+        result.mSystemWindowInsets = new Rect(0, 0, 0, 0);
+        return result;
+    }
+
+    /**
+     * Returns a copy of this WindowInsets with selected system window insets fully consumed.
+     *
+     * @param left true to consume the left system window inset
+     * @param top true to consume the top system window inset
+     * @param right true to consume the right system window inset
+     * @param bottom true to consume the bottom system window inset
+     * @return A modified copy of this WindowInsets
+     * @hide pending API
+     */
+    public WindowInsets consumeSystemWindowInsets(boolean left, boolean top,
+            boolean right, boolean bottom) {
+        if (left || top || right || bottom) {
+            final WindowInsets result = new WindowInsets(this);
+            result.mSystemWindowInsets = new Rect(left ? 0 : mSystemWindowInsets.left,
+                    top ? 0 : mSystemWindowInsets.top,
+                    right ? 0 : mSystemWindowInsets.right,
+                    bottom ? 0 : mSystemWindowInsets.bottom);
+            return result;
+        }
+        return this;
+    }
+
+    /**
+     * Returns a copy of this WindowInsets with selected system window insets replaced
+     * with new values.
+     *
+     * @param left New left inset in pixels
+     * @param top New top inset in pixels
+     * @param right New right inset in pixels
+     * @param bottom New bottom inset in pixels
+     * @return A modified copy of this WindowInsets
+     */
+    public WindowInsets replaceSystemWindowInsets(int left, int top,
+            int right, int bottom) {
+        final WindowInsets result = new WindowInsets(this);
+        result.mSystemWindowInsets = new Rect(left, top, right, bottom);
+        return result;
+    }
+
+    /**
+     * @hide
+     */
+    public WindowInsets consumeWindowDecorInsets() {
+        final WindowInsets result = new WindowInsets(this);
+        result.mWindowDecorInsets.set(0, 0, 0, 0);
+        return result;
+    }
+
+    /**
+     * @hide
+     */
+    public WindowInsets consumeWindowDecorInsets(boolean left, boolean top,
+            boolean right, boolean bottom) {
+        if (left || top || right || bottom) {
+            final WindowInsets result = new WindowInsets(this);
+            result.mWindowDecorInsets = new Rect(left ? 0 : mWindowDecorInsets.left,
+                    top ? 0 : mWindowDecorInsets.top,
+                    right ? 0 : mWindowDecorInsets.right,
+                    bottom ? 0 : mWindowDecorInsets.bottom);
+            return result;
+        }
+        return this;
+    }
+
+    /**
+     * @hide
+     */
+    public WindowInsets replaceWindowDecorInsets(int left, int top, int right, int bottom) {
+        final WindowInsets result = new WindowInsets(this);
+        result.mWindowDecorInsets = new Rect(left, top, right, bottom);
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return "WindowInsets{systemWindowInsets=" + mSystemWindowInsets + " windowDecorInsets=" +
+                mWindowDecorInsets + (isRound() ? "round}" : "}");
+    }
+}
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 53a4c0d0..d5a7d33 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -610,7 +610,10 @@
          * screen is pressed, you will receive this first touch event.  Usually
          * the first touch event is consumed by the system since the user can
          * not see what they are pressing on.
+         *
+         * @deprecated This flag has no effect.
          */
+        @Deprecated
         public static final int FLAG_TOUCHABLE_WHEN_WAKING = 0x00000040;
         
         /** Window flag: as long as this window is visible to the user, keep
diff --git a/core/java/android/view/WindowManagerInternal.java b/core/java/android/view/WindowManagerInternal.java
new file mode 100644
index 0000000..a1bd4bd
--- /dev/null
+++ b/core/java/android/view/WindowManagerInternal.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import android.hardware.display.DisplayManagerInternal;
+
+/**
+ * Window manager local system service interface.
+ *
+ * @hide Only for use within the system server.
+ */
+public abstract class WindowManagerInternal {
+    /**
+     * Request that the window manager call
+     * {@link DisplayManagerInternal#performTraversalInTransactionFromWindowManager}
+     * within a surface transaction at a later time.
+     */
+    public abstract void requestTraversalFromDisplayManager();
+}
\ No newline at end of file
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index c5a1b86c..ae7cd26 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -86,8 +86,7 @@
     public final static int FLAG_FILTERED = 0x04000000;
     public final static int FLAG_DISABLE_KEY_REPEAT = 0x08000000;
 
-    public final static int FLAG_WOKE_HERE = 0x10000000;
-    public final static int FLAG_BRIGHT_HERE = 0x20000000;
+    public final static int FLAG_INTERACTIVE = 0x20000000;
     public final static int FLAG_PASS_TO_USER = 0x40000000;
 
     // Flags used for indicating whether the internal and/or external input devices
@@ -115,20 +114,6 @@
     public final static int ACTION_PASS_TO_USER = 0x00000001;
 
     /**
-     * This key event should wake the device.
-     * To be returned from {@link #interceptKeyBeforeQueueing}.
-     * Do not return this and {@link #ACTION_GO_TO_SLEEP} or {@link #ACTION_PASS_TO_USER}.
-     */
-    public final static int ACTION_WAKE_UP = 0x00000002;
-
-    /**
-     * This key event should put the device to sleep (and engage keyguard if necessary)
-     * To be returned from {@link #interceptKeyBeforeQueueing}.
-     * Do not return this and {@link #ACTION_WAKE_UP} or {@link #ACTION_PASS_TO_USER}.
-     */
-    public final static int ACTION_GO_TO_SLEEP = 0x00000004;
-
-    /**
      * Interface to the Window Manager state associated with a particular
      * window.  You can hold on to an instance of this interface from the call
      * to prepareAddWindow() until removeWindow().
@@ -461,8 +446,6 @@
     public final int OFF_BECAUSE_OF_USER = 2;
     /** Screen turned off because of timeout */
     public final int OFF_BECAUSE_OF_TIMEOUT = 3;
-    /** Screen turned off because of proximity sensor */
-    public final int OFF_BECAUSE_OF_PROX_SENSOR = 4;
 
     /** When not otherwise specified by the activity's screenOrientation, rotation should be
      * determined by the system (that is, using sensors). */
@@ -749,12 +732,10 @@
      * because it's the most fragile.
      * @param event The key event.
      * @param policyFlags The policy flags associated with the key.
-     * @param isScreenOn True if the screen is already on
      *
-     * @return The bitwise or of the {@link #ACTION_PASS_TO_USER},
-     *      {@link #ACTION_WAKE_UP} and {@link #ACTION_GO_TO_SLEEP} flags.
+     * @return Actions flags: may be {@link #ACTION_PASS_TO_USER}.
      */
-    public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn);
+    public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags);
 
     /**
      * Called from the input reader thread before a motion is enqueued when the screen is off.
@@ -765,10 +746,9 @@
      * because it's the most fragile.
      * @param policyFlags The policy flags associated with the motion.
      *
-     * @return The bitwise or of the {@link #ACTION_PASS_TO_USER},
-     *      {@link #ACTION_WAKE_UP} and {@link #ACTION_GO_TO_SLEEP} flags.
+     * @return Actions flags: may be {@link #ACTION_PASS_TO_USER}.
      */
-    public int interceptMotionBeforeQueueingWhenScreenOff(int policyFlags);
+    public int interceptWakeMotionBeforeQueueing(long whenNanos, int policyFlags);
 
     /**
      * Called from the input dispatcher thread before a key is dispatched to a window.
@@ -916,23 +896,23 @@
     public int focusChangedLw(WindowState lastFocus, WindowState newFocus);
     
     /**
-     * Called after the screen turns off.
+     * Called when the device is going to sleep.
      *
      * @param why {@link #OFF_BECAUSE_OF_USER} or
      * {@link #OFF_BECAUSE_OF_TIMEOUT}.
      */
-    public void screenTurnedOff(int why);
+    public void goingToSleep(int why);
 
     public interface ScreenOnListener {
         void onScreenOn();
     }
 
     /**
-     * Called when the power manager would like to turn the screen on.
+     * Called when the device is waking up.
      * Must call back on the listener to tell it when the higher-level system
      * is ready for the screen to go on (i.e. the lock screen is shown).
      */
-    public void screenTurningOn(ScreenOnListener screenOnListener);
+    public void wakingUp(ScreenOnListener screenOnListener);
 
     /**
      * Return whether the screen is about to turn on or is currently on.
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index 00f4adb..879e58f 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -177,7 +177,8 @@
                     userId = UserHandle.myUserId();
                 }
                 IBinder iBinder = ServiceManager.getService(Context.ACCESSIBILITY_SERVICE);
-                IAccessibilityManager service = IAccessibilityManager.Stub.asInterface(iBinder);
+                IAccessibilityManager service = iBinder == null
+                        ? null : IAccessibilityManager.Stub.asInterface(iBinder);
                 sInstance = new AccessibilityManager(context, service, userId);
             }
         }
@@ -197,10 +198,14 @@
         mHandler = new MyHandler(context.getMainLooper());
         mService = service;
         mUserId = userId;
-
+        if (mService == null) {
+            mIsEnabled = false;
+        }
         try {
-            final int stateFlags = mService.addClient(mClient, userId);
-            setState(stateFlags);
+            if (mService != null) {
+                final int stateFlags = mService.addClient(mClient, userId);
+                setState(stateFlags);
+            }
         } catch (RemoteException re) {
             Log.e(LOG_TAG, "AccessibilityManagerService is dead", re);
         }
@@ -322,14 +327,16 @@
     public List<AccessibilityServiceInfo> getInstalledAccessibilityServiceList() {
         List<AccessibilityServiceInfo> services = null;
         try {
-            services = mService.getInstalledAccessibilityServiceList(mUserId);
-            if (DEBUG) {
-                Log.i(LOG_TAG, "Installed AccessibilityServices " + services);
+            if (mService != null) {
+                services = mService.getInstalledAccessibilityServiceList(mUserId);
+                if (DEBUG) {
+                    Log.i(LOG_TAG, "Installed AccessibilityServices " + services);
+                }
             }
         } catch (RemoteException re) {
             Log.e(LOG_TAG, "Error while obtaining the installed AccessibilityServices. ", re);
         }
-        return Collections.unmodifiableList(services);
+        return services != null ? Collections.unmodifiableList(services) : Collections.EMPTY_LIST;
     }
 
     /**
@@ -349,14 +356,16 @@
             int feedbackTypeFlags) {
         List<AccessibilityServiceInfo> services = null;
         try {
-            services = mService.getEnabledAccessibilityServiceList(feedbackTypeFlags, mUserId);
-            if (DEBUG) {
-                Log.i(LOG_TAG, "Installed AccessibilityServices " + services);
+            if (mService != null) {
+                services = mService.getEnabledAccessibilityServiceList(feedbackTypeFlags, mUserId);
+                if (DEBUG) {
+                    Log.i(LOG_TAG, "Installed AccessibilityServices " + services);
+                }
             }
         } catch (RemoteException re) {
             Log.e(LOG_TAG, "Error while obtaining the installed AccessibilityServices. ", re);
         }
-        return Collections.unmodifiableList(services);
+        return services != null ? Collections.unmodifiableList(services) : Collections.EMPTY_LIST;
     }
 
     /**
@@ -466,6 +475,9 @@
      */
     public int addAccessibilityInteractionConnection(IWindow windowToken,
             IAccessibilityInteractionConnection connection) {
+        if (mService == null) {
+            return View.NO_ID;
+        }
         try {
             return mService.addAccessibilityInteractionConnection(windowToken, connection, mUserId);
         } catch (RemoteException re) {
@@ -482,7 +494,9 @@
      */
     public void removeAccessibilityInteractionConnection(IWindow windowToken) {
         try {
-            mService.removeAccessibilityInteractionConnection(windowToken);
+            if (mService != null) {
+                mService.removeAccessibilityInteractionConnection(windowToken);
+            }
         } catch (RemoteException re) {
             Log.e(LOG_TAG, "Error while removing an accessibility interaction connection. ", re);
         }
diff --git a/core/java/android/webkit/EventLogTags.logtags b/core/java/android/webkit/EventLogTags.logtags
index b0b5493..a90aebd 100644
--- a/core/java/android/webkit/EventLogTags.logtags
+++ b/core/java/android/webkit/EventLogTags.logtags
@@ -8,3 +8,4 @@
 # 70103- used by the browser app itself
 
 70150 browser_snap_center
+70151 exp_det_attempt_to_call_object_getclass (app_signature|3)
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 25a43a6..bbaa33d 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -3039,7 +3039,7 @@
 
     @Override
     public boolean onKeyUp(int keyCode, KeyEvent event) {
-        if (KeyEvent.isConfirmKey(keyCode)) {
+        if (event.isConfirmKey()) {
             if (!isEnabled()) {
                 return true;
             }
diff --git a/core/java/android/widget/Gallery.java b/core/java/android/widget/Gallery.java
index 78ba6e0..6dd93a7 100644
--- a/core/java/android/widget/Gallery.java
+++ b/core/java/android/widget/Gallery.java
@@ -1228,7 +1228,7 @@
 
     @Override
     public boolean onKeyUp(int keyCode, KeyEvent event) {
-        if (KeyEvent.isConfirmKey(keyCode)) {
+        if (event.isConfirmKey()) {
             if (mReceivedInvokeKeyDown) {
                 if (mItemCount > 0) {
                     dispatchPress(mSelectedChild);
diff --git a/core/java/android/widget/ListPopupWindow.java b/core/java/android/widget/ListPopupWindow.java
index 66fe46f..13f3eb6 100644
--- a/core/java/android/widget/ListPopupWindow.java
+++ b/core/java/android/widget/ListPopupWindow.java
@@ -843,7 +843,7 @@
             // to select one of its items
             if (keyCode != KeyEvent.KEYCODE_SPACE
                     && (mDropDownList.getSelectedItemPosition() >= 0
-                            || !KeyEvent.isConfirmKey(keyCode))) {
+                            || !event.isConfirmKey())) {
                 int curIndex = mDropDownList.getSelectedItemPosition();
                 boolean consumed;
 
@@ -931,7 +931,7 @@
     public boolean onKeyUp(int keyCode, KeyEvent event) {
         if (isShowing() && mDropDownList.getSelectedItemPosition() >= 0) {
             boolean consumed = mDropDownList.onKeyUp(keyCode, event);
-            if (consumed && KeyEvent.isConfirmKey(keyCode)) {
+            if (consumed && event.isConfirmKey()) {
                 // if the list accepts the key events and the key event was a click, the text view
                 // gets the selected item from the drop down as its content
                 dismiss();
diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java
index 26c5732..2c44703 100644
--- a/core/java/android/widget/NumberPicker.java
+++ b/core/java/android/widget/NumberPicker.java
@@ -427,12 +427,12 @@
      * Flag whether to ignore move events - we ignore such when we show in IME
      * to prevent the content from scrolling.
      */
-    private boolean mIngonreMoveEvents;
+    private boolean mIgnoreMoveEvents;
 
     /**
-     * Flag whether to show soft input on tap.
+     * Flag whether to perform a click on tap.
      */
-    private boolean mShowSoftInputOnTap;
+    private boolean mPerformClickOnTap;
 
     /**
      * The top of the top selection divider.
@@ -808,8 +808,8 @@
                 mInputText.setVisibility(View.INVISIBLE);
                 mLastDownOrMoveEventY = mLastDownEventY = event.getY();
                 mLastDownEventTime = event.getEventTime();
-                mIngonreMoveEvents = false;
-                mShowSoftInputOnTap = false;
+                mIgnoreMoveEvents = false;
+                mPerformClickOnTap = false;
                 // Handle pressed state before any state change.
                 if (mLastDownEventY < mTopSelectionDividerTop) {
                     if (mScrollState == OnScrollListener.SCROLL_STATE_IDLE) {
@@ -840,7 +840,7 @@
                     postChangeCurrentByOneFromLongPress(
                             true, ViewConfiguration.getLongPressTimeout());
                 } else {
-                    mShowSoftInputOnTap = true;
+                    mPerformClickOnTap = true;
                     postBeginSoftInputOnLongPressCommand();
                 }
                 return true;
@@ -861,7 +861,7 @@
         int action = event.getActionMasked();
         switch (action) {
             case MotionEvent.ACTION_MOVE: {
-                if (mIngonreMoveEvents) {
+                if (mIgnoreMoveEvents) {
                     break;
                 }
                 float currentMoveY = event.getY();
@@ -893,9 +893,9 @@
                     int deltaMoveY = (int) Math.abs(eventY - mLastDownEventY);
                     long deltaTime = event.getEventTime() - mLastDownEventTime;
                     if (deltaMoveY <= mTouchSlop && deltaTime < ViewConfiguration.getTapTimeout()) {
-                        if (mShowSoftInputOnTap) {
-                            mShowSoftInputOnTap = false;
-                            showSoftInput();
+                        if (mPerformClickOnTap) {
+                            mPerformClickOnTap = false;
+                            performClick();
                         } else {
                             int selectorIndexOffset = (eventY / mSelectorElementHeight)
                                     - SELECTOR_MIDDLE_ITEM_INDEX;
@@ -1188,6 +1188,27 @@
         setValueInternal(value, false);
     }
 
+    @Override
+    public boolean performClick() {
+        if (!mHasSelectorWheel) {
+            return super.performClick();
+        } else if (!super.performClick()) {
+            showSoftInput();
+        }
+        return true;
+    }
+
+    @Override
+    public boolean performLongClick() {
+        if (!mHasSelectorWheel) {
+            return super.performLongClick();
+        } else if (!super.performLongClick()) {
+            showSoftInput();
+            mIgnoreMoveEvents = true;
+        }
+        return true;
+    }
+
     /**
      * Shows the soft input for its input text.
      */
@@ -2175,8 +2196,7 @@
 
         @Override
         public void run() {
-            showSoftInput();
-            mIngonreMoveEvents = true;
+            performLongClick();
         }
     }
 
@@ -2304,7 +2324,14 @@
                         }
                         case AccessibilityNodeInfo.ACTION_CLICK: {
                             if (NumberPicker.this.isEnabled()) {
-                                showSoftInput();
+                                performClick();
+                                return true;
+                            }
+                            return false;
+                        }
+                        case AccessibilityNodeInfo.ACTION_LONG_CLICK: {
+                            if (NumberPicker.this.isEnabled()) {
+                                performLongClick();
                                 return true;
                             }
                             return false;
diff --git a/core/java/android/widget/ShareActionProvider.java b/core/java/android/widget/ShareActionProvider.java
index bdaaa01..fd6ca4c 100644
--- a/core/java/android/widget/ShareActionProvider.java
+++ b/core/java/android/widget/ShareActionProvider.java
@@ -161,9 +161,11 @@
     @Override
     public View onCreateActionView() {
         // Create the view and set its data model.
-        ActivityChooserModel dataModel = ActivityChooserModel.get(mContext, mShareHistoryFileName);
         ActivityChooserView activityChooserView = new ActivityChooserView(mContext);
-        activityChooserView.setActivityChooserModel(dataModel);
+        if (!activityChooserView.isInEditMode()) {
+            ActivityChooserModel dataModel = ActivityChooserModel.get(mContext, mShareHistoryFileName);
+            activityChooserView.setActivityChooserModel(dataModel);
+        }
 
         // Lookup and set the expand action icon.
         TypedValue outTypedValue = new TypedValue();
diff --git a/core/java/android/widget/SpellChecker.java b/core/java/android/widget/SpellChecker.java
index 1cda631..b204dfd 100644
--- a/core/java/android/widget/SpellChecker.java
+++ b/core/java/android/widget/SpellChecker.java
@@ -731,14 +731,10 @@
                 }
             }
 
-            if (scheduleOtherSpellCheck && wordStart <= end) {
+            if (scheduleOtherSpellCheck) {
                 // Update range span: start new spell check from last wordStart
                 setRangeSpan(editable, wordStart, end);
             } else {
-                if (DBG && scheduleOtherSpellCheck) {
-                    Log.w(TAG, "Trying to schedule spellcheck for invalid region, from "
-                            + wordStart + " to " + end);
-                }
                 removeRangeSpan(editable);
             }
 
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 5ece016..8460375 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -710,19 +710,19 @@
                     break;
 
                 case com.android.internal.R.styleable.TextAppearance_shadowColor:
-                    shadowcolor = a.getInt(attr, 0);
+                    shadowcolor = appearance.getInt(attr, 0);
                     break;
 
                 case com.android.internal.R.styleable.TextAppearance_shadowDx:
-                    dx = a.getFloat(attr, 0);
+                    dx = appearance.getFloat(attr, 0);
                     break;
 
                 case com.android.internal.R.styleable.TextAppearance_shadowDy:
-                    dy = a.getFloat(attr, 0);
+                    dy = appearance.getFloat(attr, 0);
                     break;
 
                 case com.android.internal.R.styleable.TextAppearance_shadowRadius:
-                    r = a.getFloat(attr, 0);
+                    r = appearance.getFloat(attr, 0);
                     break;
                 }
             }
diff --git a/core/java/com/android/internal/app/ActionBarImpl.java b/core/java/com/android/internal/app/ActionBarImpl.java
index 066d6c3..ad45894 100644
--- a/core/java/com/android/internal/app/ActionBarImpl.java
+++ b/core/java/com/android/internal/app/ActionBarImpl.java
@@ -174,6 +174,15 @@
         init(dialog.getWindow().getDecorView());
     }
 
+    /**
+     * Only for edit mode.
+     * @hide
+     */
+    public ActionBarImpl(View layout) {
+        assert layout.isInEditMode();
+        init(layout);
+    }
+
     private void init(View decor) {
         mContext = decor.getContext();
         mOverlayLayout = (ActionBarOverlayLayout) decor.findViewById(
@@ -559,8 +568,8 @@
             return;
         }
 
-        final FragmentTransaction trans = mActivity.getFragmentManager().beginTransaction()
-                .disallowAddToBackStack();
+        final FragmentTransaction trans = mActionView.isInEditMode() ? null :
+                mActivity.getFragmentManager().beginTransaction().disallowAddToBackStack();
 
         if (mSelectedTab == tab) {
             if (mSelectedTab != null) {
@@ -578,7 +587,7 @@
             }
         }
 
-        if (!trans.isEmpty()) {
+        if (trans != null && !trans.isEmpty()) {
             trans.commit();
         }
     }
diff --git a/core/java/com/android/internal/app/AlertController.java b/core/java/com/android/internal/app/AlertController.java
index fe532b0..19c0a44 100644
--- a/core/java/com/android/internal/app/AlertController.java
+++ b/core/java/com/android/internal/app/AlertController.java
@@ -26,6 +26,7 @@
 import android.content.res.TypedArray;
 import android.database.Cursor;
 import android.graphics.drawable.Drawable;
+import android.os.Build;
 import android.os.Handler;
 import android.os.Message;
 import android.text.TextUtils;
@@ -38,6 +39,7 @@
 import android.view.ViewGroup;
 import android.view.ViewGroup.LayoutParams;
 import android.view.Window;
+import android.view.WindowInsets;
 import android.view.WindowManager;
 import android.widget.AdapterView;
 import android.widget.AdapterView.OnItemClickListener;
@@ -239,6 +241,7 @@
         }
         mWindow.setContentView(mAlertDialogLayout);
         setupView();
+        setupDecor();
     }
     
     public void setTitle(CharSequence title) {
@@ -389,7 +392,28 @@
     public boolean onKeyUp(int keyCode, KeyEvent event) {
         return mScrollView != null && mScrollView.executeKeyEvent(event);
     }
-    
+
+    private void setupDecor() {
+        final View decor = mWindow.getDecorView();
+        final View parent = mWindow.findViewById(R.id.parentPanel);
+        if (parent != null && decor != null) {
+            decor.setOnApplyWindowInsetsListener(new View.OnApplyWindowInsetsListener() {
+                @Override
+                public WindowInsets onApplyWindowInsets(View view, WindowInsets insets) {
+                    if (insets.isRound()) {
+                        // TODO: Get the padding as a function of the window size.
+                        int roundOffset = mContext.getResources().getDimensionPixelOffset(
+                                R.dimen.alert_dialog_round_padding);
+                        parent.setPadding(roundOffset, roundOffset, roundOffset, roundOffset);
+                    }
+                    return insets.consumeSystemWindowInsets();
+                }
+            });
+            decor.setFitsSystemWindows(true);
+            decor.requestApplyInsets();
+        }
+    }
+
     private void setupView() {
         LinearLayout contentPanel = (LinearLayout) mWindow.findViewById(R.id.contentPanel);
         setupContent(contentPanel);
@@ -601,25 +625,36 @@
             View buttonPanel) {
         
         /* Get all the different background required */
-        int fullDark = a.getResourceId(
-                R.styleable.AlertDialog_fullDark, R.drawable.popup_full_dark);
-        int topDark = a.getResourceId(
-                R.styleable.AlertDialog_topDark, R.drawable.popup_top_dark);
-        int centerDark = a.getResourceId(
-                R.styleable.AlertDialog_centerDark, R.drawable.popup_center_dark);
-        int bottomDark = a.getResourceId(
-                R.styleable.AlertDialog_bottomDark, R.drawable.popup_bottom_dark);
-        int fullBright = a.getResourceId(
-                R.styleable.AlertDialog_fullBright, R.drawable.popup_full_bright);
-        int topBright = a.getResourceId(
-                R.styleable.AlertDialog_topBright, R.drawable.popup_top_bright);
-        int centerBright = a.getResourceId(
-                R.styleable.AlertDialog_centerBright, R.drawable.popup_center_bright);
-        int bottomBright = a.getResourceId(
-                R.styleable.AlertDialog_bottomBright, R.drawable.popup_bottom_bright);
-        int bottomMedium = a.getResourceId(
-                R.styleable.AlertDialog_bottomMedium, R.drawable.popup_bottom_medium);
-        
+        int fullDark = 0;
+        int topDark = 0;
+        int centerDark = 0;
+        int bottomDark = 0;
+        int fullBright = 0;
+        int topBright = 0;
+        int centerBright = 0;
+        int bottomBright = 0;
+        int bottomMedium = 0;
+        if (mContext.getApplicationInfo().targetSdkVersion <= Build.VERSION_CODES.KITKAT) {
+            fullDark = R.drawable.popup_full_dark;
+            topDark = R.drawable.popup_top_dark;
+            centerDark = R.drawable.popup_center_dark;
+            bottomDark = R.drawable.popup_bottom_dark;
+            fullBright = R.drawable.popup_full_bright;
+            topBright = R.drawable.popup_top_bright;
+            centerBright = R.drawable.popup_center_bright;
+            bottomBright = R.drawable.popup_bottom_bright;
+            bottomMedium = R.drawable.popup_bottom_medium;
+        }
+        fullDark = a.getResourceId(R.styleable.AlertDialog_fullDark, fullDark);
+        topDark = a.getResourceId(R.styleable.AlertDialog_topDark, topDark);
+        centerDark = a.getResourceId(R.styleable.AlertDialog_centerDark, centerDark);
+        bottomDark = a.getResourceId(R.styleable.AlertDialog_bottomDark, bottomDark);
+        fullBright = a.getResourceId(R.styleable.AlertDialog_fullBright, fullBright);
+        topBright = a.getResourceId(R.styleable.AlertDialog_topBright, topBright);
+        centerBright = a.getResourceId(R.styleable.AlertDialog_centerBright, centerBright);
+        bottomBright = a.getResourceId(R.styleable.AlertDialog_bottomBright, bottomBright);
+        bottomMedium = a.getResourceId(R.styleable.AlertDialog_bottomMedium, bottomMedium);
+
         /*
          * We now set the background of all of the sections of the alert.
          * First collect together each section that is being displayed along
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index 43c4b49..5413113 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -41,11 +41,10 @@
     void noteVibratorOff(int uid);
     void noteStartGps(int uid);
     void noteStopGps(int uid);
-    void noteScreenOn();
+    void noteScreenState(int state);
     void noteScreenBrightness(int brightness);
-    void noteScreenOff();
-    void noteInputEvent();
     void noteUserActivity(int uid, int event);
+    void noteInteractive(boolean interactive);
     void notePhoneOn();
     void notePhoneOff();
     void notePhoneSignalStrength(in SignalStrength signalStrength);
diff --git a/core/java/com/android/internal/app/ProcessStats.java b/core/java/com/android/internal/app/ProcessStats.java
index a13a1cb..a87992a 100644
--- a/core/java/com/android/internal/app/ProcessStats.java
+++ b/core/java/com/android/internal/app/ProcessStats.java
@@ -1004,7 +1004,7 @@
                 for (int iproc=pkgState.mProcesses.size()-1; iproc>=0; iproc--) {
                     ProcessState ps = pkgState.mProcesses.valueAt(iproc);
                     if (ps.isInUse() || ps.mCommonProcess.isInUse()) {
-                        ps.resetSafely(now);
+                        pkgState.mProcesses.valueAt(iproc).resetSafely(now);
                     } else {
                         pkgState.mProcesses.valueAt(iproc).makeDead();
                         pkgState.mProcesses.removeAt(iproc);
@@ -1013,7 +1013,7 @@
                 for (int isvc=pkgState.mServices.size()-1; isvc>=0; isvc--) {
                     ServiceState ss = pkgState.mServices.valueAt(isvc);
                     if (ss.isInUse()) {
-                        ss.resetSafely(now);
+                        pkgState.mServices.valueAt(isvc).resetSafely(now);
                     } else {
                         pkgState.mServices.removeAt(isvc);
                     }
@@ -3014,7 +3014,7 @@
         }
 
         public boolean isInUse() {
-            return mOwner != null || mRestarting;
+            return mOwner != null;
         }
 
         void add(ServiceState other) {
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 2e5fcec..9c82fac 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -26,6 +26,7 @@
 import android.os.BatteryStats;
 import android.os.FileUtils;
 import android.os.Handler;
+import android.os.Looper;
 import android.os.Message;
 import android.os.Parcel;
 import android.os.ParcelFormatException;
@@ -44,6 +45,7 @@
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.TimeUtils;
+import android.view.Display;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.net.NetworkStatsFactory;
@@ -84,7 +86,7 @@
     private static final int MAGIC = 0xBA757475; // 'BATSTATS'
 
     // Current on-disk Parcel version
-    private static final int VERSION = 67 + (USE_OLD_HISTORY ? 1000 : 0);
+    private static final int VERSION = 68 + (USE_OLD_HISTORY ? 1000 : 0);
 
     // Maximum number of items we will record in the history.
     private static final int MAX_HISTORY_ITEMS = 2000;
@@ -113,6 +115,10 @@
     }
 
     final class MyHandler extends Handler {
+        public MyHandler(Looper looper) {
+            super(looper, null, true);
+        }
+
         @Override
         public void handleMessage(Message msg) {
             BatteryCallback cb = mCallback;
@@ -206,13 +212,14 @@
     long mRealtimeStart;
     long mLastRealtime;
 
-    boolean mScreenOn;
+    int mScreenState = Display.STATE_UNKNOWN;
     StopwatchTimer mScreenOnTimer;
 
     int mScreenBrightnessBin = -1;
     final StopwatchTimer[] mScreenBrightnessTimer = new StopwatchTimer[NUM_SCREEN_BRIGHTNESS_BINS];
 
-    Counter mInputEventCounter;
+    boolean mInteractive;
+    StopwatchTimer mInteractiveTimer;
 
     boolean mPhoneOn;
     StopwatchTimer mPhoneOnTimer;
@@ -1737,7 +1744,7 @@
     public int startAddingCpuLocked() {
         mHandler.removeMessages(MSG_UPDATE_WAKELOCKS);
 
-        if (mScreenOn) {
+        if (mScreenState == Display.STATE_ON) {
             return 0;
         }
 
@@ -1912,46 +1919,49 @@
         getUidStatsLocked(uid).noteStopGps();
     }
 
-    public void noteScreenOnLocked() {
-        if (!mScreenOn) {
-            mHistoryCur.states |= HistoryItem.STATE_SCREEN_ON_FLAG;
-            if (DEBUG_HISTORY) Slog.v(TAG, "Screen on to: "
-                    + Integer.toHexString(mHistoryCur.states));
-            addHistoryRecordLocked(SystemClock.elapsedRealtime());
-            mScreenOn = true;
-            mScreenOnTimer.startRunningLocked(this);
-            if (mScreenBrightnessBin >= 0) {
-                mScreenBrightnessTimer[mScreenBrightnessBin].startRunningLocked(this);
-            }
+    public void noteScreenStateLocked(int state) {
+        if (mScreenState != state) {
+            final int oldState = mScreenState;
+            mScreenState = state;
+            if (DEBUG) Slog.v(TAG, "Screen state: oldState=" + Display.stateToString(oldState)
+                    + ", newState=" + Display.stateToString(state));
 
-            // Fake a wake lock, so we consider the device waked as long
-            // as the screen is on.
-            noteStartWakeLocked(-1, -1, "dummy", WAKE_TYPE_PARTIAL);
-            
-            // Update discharge amounts.
-            if (mOnBatteryInternal) {
-                updateDischargeScreenLevelsLocked(false, true);
-            }
-        }
-    }
+            if (state == Display.STATE_ON) {
+                // Screen turning on.
+                mHistoryCur.states |= HistoryItem.STATE_SCREEN_ON_FLAG;
+                if (DEBUG_HISTORY) Slog.v(TAG, "Screen on to: "
+                        + Integer.toHexString(mHistoryCur.states));
+                addHistoryRecordLocked(SystemClock.elapsedRealtime());
+                mScreenOnTimer.startRunningLocked(this);
+                if (mScreenBrightnessBin >= 0) {
+                    mScreenBrightnessTimer[mScreenBrightnessBin].startRunningLocked(this);
+                }
 
-    public void noteScreenOffLocked() {
-        if (mScreenOn) {
-            mHistoryCur.states &= ~HistoryItem.STATE_SCREEN_ON_FLAG;
-            if (DEBUG_HISTORY) Slog.v(TAG, "Screen off to: "
-                    + Integer.toHexString(mHistoryCur.states));
-            addHistoryRecordLocked(SystemClock.elapsedRealtime());
-            mScreenOn = false;
-            mScreenOnTimer.stopRunningLocked(this);
-            if (mScreenBrightnessBin >= 0) {
-                mScreenBrightnessTimer[mScreenBrightnessBin].stopRunningLocked(this);
-            }
+                // Fake a wake lock, so we consider the device waked as long
+                // as the screen is on.
+                noteStartWakeLocked(-1, -1, "dummy", WAKE_TYPE_PARTIAL);
 
-            noteStopWakeLocked(-1, -1, "dummy", WAKE_TYPE_PARTIAL);
-            
-            // Update discharge amounts.
-            if (mOnBatteryInternal) {
-                updateDischargeScreenLevelsLocked(true, false);
+                // Update discharge amounts.
+                if (mOnBatteryInternal) {
+                    updateDischargeScreenLevelsLocked(false, true);
+                }
+            } else if (oldState == Display.STATE_ON) {
+                // Screen turning off or dozing.
+                mHistoryCur.states &= ~HistoryItem.STATE_SCREEN_ON_FLAG;
+                if (DEBUG_HISTORY) Slog.v(TAG, "Screen off to: "
+                        + Integer.toHexString(mHistoryCur.states));
+                addHistoryRecordLocked(SystemClock.elapsedRealtime());
+                mScreenOnTimer.stopRunningLocked(this);
+                if (mScreenBrightnessBin >= 0) {
+                    mScreenBrightnessTimer[mScreenBrightnessBin].stopRunningLocked(this);
+                }
+
+                noteStopWakeLocked(-1, -1, "dummy", WAKE_TYPE_PARTIAL);
+
+                // Update discharge amounts.
+                if (mOnBatteryInternal) {
+                    updateDischargeScreenLevelsLocked(true, false);
+                }
             }
         }
     }
@@ -1967,7 +1977,7 @@
             if (DEBUG_HISTORY) Slog.v(TAG, "Screen brightness " + bin + " to: "
                     + Integer.toHexString(mHistoryCur.states));
             addHistoryRecordLocked(SystemClock.elapsedRealtime());
-            if (mScreenOn) {
+            if (mScreenState == Display.STATE_ON) {
                 if (mScreenBrightnessBin >= 0) {
                     mScreenBrightnessTimer[mScreenBrightnessBin].stopRunningLocked(this);
                 }
@@ -1977,14 +1987,22 @@
         }
     }
 
-    public void noteInputEventAtomic() {
-        mInputEventCounter.stepAtomic();
-    }
-
     public void noteUserActivityLocked(int uid, int event) {
         getUidStatsLocked(uid).noteUserActivityLocked(event);
     }
 
+    public void noteInteractiveLocked(boolean interactive) {
+        if (mInteractive != interactive) {
+            mInteractive = interactive;
+            if (DEBUG) Slog.v(TAG, "Interactive: " + interactive);
+            if (interactive) {
+                mInteractiveTimer.startRunningLocked(this);
+            } else {
+                mInteractiveTimer.stopRunningLocked(this);
+            }
+        }
+    }
+
     public void notePhoneOnLocked() {
         if (!mPhoneOn) {
             mHistoryCur.states |= HistoryItem.STATE_PHONE_IN_CALL_FLAG;
@@ -2524,8 +2542,8 @@
                 batteryRealtime, which);
     }
 
-    @Override public int getInputEventCount(int which) {
-        return mInputEventCounter.getCountLocked(which);
+    @Override public long getInteractiveTime(long batteryRealtime, int which) {
+        return mInteractiveTimer.getTotalTimeLocked(batteryRealtime, which);
     }
 
     @Override public long getPhoneOnTime(long batteryRealtime, int which) {
@@ -4487,15 +4505,14 @@
         }
     }
 
-    public BatteryStatsImpl(String filename) {
+    public BatteryStatsImpl(String filename, Handler handler) {
         mFile = new JournaledFile(new File(filename), new File(filename + ".tmp"));
-        mHandler = new MyHandler();
+        mHandler = new MyHandler(handler.getLooper());
         mStartCount++;
         mScreenOnTimer = new StopwatchTimer(null, -1, null, mUnpluggables);
         for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
             mScreenBrightnessTimer[i] = new StopwatchTimer(null, -100-i, null, mUnpluggables);
         }
-        mInputEventCounter = new Counter(mUnpluggables);
         mPhoneOnTimer = new StopwatchTimer(null, -2, null, mUnpluggables);
         for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
             mPhoneSignalStrengthsTimer[i] = new StopwatchTimer(null, -200-i, null, mUnpluggables);
@@ -4512,6 +4529,7 @@
         mBluetoothOnTimer = new StopwatchTimer(null, -5, null, mUnpluggables);
         mAudioOnTimer = new StopwatchTimer(null, -6, null, mUnpluggables);
         mVideoOnTimer = new StopwatchTimer(null, -7, null, mUnpluggables);
+        mInteractiveTimer = new StopwatchTimer(null, -8, null, mUnpluggables);
         mOnBattery = mOnBatteryInternal = false;
         initTimes();
         mTrackBatteryPastUptime = 0;
@@ -4644,7 +4662,7 @@
     }
 
     public boolean isScreenOn() {
-        return mScreenOn;
+        return mScreenState == Display.STATE_ON;
     }
 
     void initTimes() {
@@ -4672,7 +4690,7 @@
         for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
             mScreenBrightnessTimer[i].reset(this, false);
         }
-        mInputEventCounter.reset(false);
+        mInteractiveTimer.reset(this, false);
         mPhoneOnTimer.reset(this, false);
         mAudioOnTimer.reset(this, false);
         mVideoOnTimer.reset(this, false);
@@ -4748,6 +4766,7 @@
         long uptime = SystemClock.uptimeMillis() * 1000;
         long mSecRealtime = SystemClock.elapsedRealtime();
         long realtime = mSecRealtime * 1000;
+        final boolean screenOn = mScreenState == Display.STATE_ON;
         if (onBattery) {
             // We will reset our status if we are unplugging after the
             // battery was last full, or the level is at 100, or
@@ -4772,7 +4791,7 @@
             mUnpluggedBatteryUptime = getBatteryUptimeLocked(uptime);
             mUnpluggedBatteryRealtime = getBatteryRealtimeLocked(realtime);
             mDischargeCurrentLevel = mDischargeUnplugLevel = level;
-            if (mScreenOn) {
+            if (screenOn) {
                 mDischargeScreenOnUnplugLevel = level;
                 mDischargeScreenOffUnplugLevel = 0;
             } else {
@@ -4797,7 +4816,7 @@
                 mLowDischargeAmountSinceCharge += mDischargeUnplugLevel-level-1;
                 mHighDischargeAmountSinceCharge += mDischargeUnplugLevel-level;
             }
-            updateDischargeScreenLevelsLocked(mScreenOn, mScreenOn);
+            updateDischargeScreenLevelsLocked(screenOn, screenOn);
             doPlugLocked(realtime, getBatteryUptimeLocked(uptime), getBatteryRealtimeLocked(realtime));
         }
         if (doWrite || (mLastWriteTime + (60 * 1000)) < mSecRealtime) {
@@ -5100,7 +5119,7 @@
     public int getDischargeAmountScreenOn() {
         synchronized(this) {
             int val = mDischargeAmountScreenOn;
-            if (mOnBattery && mScreenOn
+            if (mOnBattery && mScreenState == Display.STATE_ON
                     && mDischargeCurrentLevel < mDischargeScreenOnUnplugLevel) {
                 val += mDischargeScreenOnUnplugLevel-mDischargeCurrentLevel;
             }
@@ -5111,7 +5130,7 @@
     public int getDischargeAmountScreenOnSinceCharge() {
         synchronized(this) {
             int val = mDischargeAmountScreenOnSinceCharge;
-            if (mOnBattery && mScreenOn
+            if (mOnBattery && mScreenState == Display.STATE_ON
                     && mDischargeCurrentLevel < mDischargeScreenOnUnplugLevel) {
                 val += mDischargeScreenOnUnplugLevel-mDischargeCurrentLevel;
             }
@@ -5122,7 +5141,7 @@
     public int getDischargeAmountScreenOff() {
         synchronized(this) {
             int val = mDischargeAmountScreenOff;
-            if (mOnBattery && !mScreenOn
+            if (mOnBattery && mScreenState != Display.STATE_ON
                     && mDischargeCurrentLevel < mDischargeScreenOffUnplugLevel) {
                 val += mDischargeScreenOffUnplugLevel-mDischargeCurrentLevel;
             }
@@ -5133,7 +5152,7 @@
     public int getDischargeAmountScreenOffSinceCharge() {
         synchronized(this) {
             int val = mDischargeAmountScreenOffSinceCharge;
-            if (mOnBattery && !mScreenOn
+            if (mOnBattery && mScreenState != Display.STATE_ON
                     && mDischargeCurrentLevel < mDischargeScreenOffUnplugLevel) {
                 val += mDischargeScreenOffUnplugLevel-mDischargeCurrentLevel;
             }
@@ -5517,12 +5536,13 @@
 
         mStartCount++;
 
-        mScreenOn = false;
+        mScreenState = Display.STATE_UNKNOWN;
         mScreenOnTimer.readSummaryFromParcelLocked(in);
         for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
             mScreenBrightnessTimer[i].readSummaryFromParcelLocked(in);
         }
-        mInputEventCounter.readSummaryFromParcelLocked(in);
+        mInteractive = false;
+        mInteractiveTimer.readSummaryFromParcelLocked(in);
         mPhoneOn = false;
         mPhoneOnTimer.readSummaryFromParcelLocked(in);
         for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
@@ -5743,7 +5763,7 @@
         for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
             mScreenBrightnessTimer[i].writeSummaryFromParcelLocked(out, NOWREAL);
         }
-        mInputEventCounter.writeSummaryFromParcelLocked(out);
+        mInteractiveTimer.writeSummaryFromParcelLocked(out, NOWREAL);
         mPhoneOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
         for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
             mPhoneSignalStrengthsTimer[i].writeSummaryFromParcelLocked(out, NOWREAL);
@@ -5965,13 +5985,12 @@
         mBatteryLastUptime = 0;
         mBatteryRealtime = in.readLong();
         mBatteryLastRealtime = 0;
-        mScreenOn = false;
+        mScreenState = Display.STATE_UNKNOWN;
         mScreenOnTimer = new StopwatchTimer(null, -1, null, mUnpluggables, in);
         for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
             mScreenBrightnessTimer[i] = new StopwatchTimer(null, -100-i,
                     null, mUnpluggables, in);
         }
-        mInputEventCounter = new Counter(mUnpluggables, in);
         mPhoneOn = false;
         mPhoneOnTimer = new StopwatchTimer(null, -2, null, mUnpluggables, in);
         for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
@@ -5987,11 +6006,17 @@
             mNetworkActivityCounters[i] = new LongSamplingCounter(mUnpluggables, in);
         }
         mWifiOn = false;
-        mWifiOnTimer = new StopwatchTimer(null, -2, null, mUnpluggables, in);
+        mWifiOnTimer = new StopwatchTimer(null, -3, null, mUnpluggables, in);
         mGlobalWifiRunning = false;
-        mGlobalWifiRunningTimer = new StopwatchTimer(null, -2, null, mUnpluggables, in);
+        mGlobalWifiRunningTimer = new StopwatchTimer(null, -4, null, mUnpluggables, in);
         mBluetoothOn = false;
-        mBluetoothOnTimer = new StopwatchTimer(null, -2, null, mUnpluggables, in);
+        mBluetoothOnTimer = new StopwatchTimer(null, -5, null, mUnpluggables, in);
+        mAudioOn = false;
+        mAudioOnTimer = new StopwatchTimer(null, -6, null, mUnpluggables);
+        mVideoOn = false;
+        mVideoOnTimer = new StopwatchTimer(null, -7, null, mUnpluggables);
+        mInteractive = false;
+        mInteractiveTimer = new StopwatchTimer(null, -8, null, mUnpluggables, in);
         mUptime = in.readLong();
         mUptimeStart = in.readLong();
         mLastUptime = 0;
@@ -6084,7 +6109,7 @@
         for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
             mScreenBrightnessTimer[i].writeToParcel(out, batteryRealtime);
         }
-        mInputEventCounter.writeToParcel(out);
+        mInteractiveTimer.writeToParcel(out, batteryRealtime);
         mPhoneOnTimer.writeToParcel(out, batteryRealtime);
         for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
             mPhoneSignalStrengthsTimer[i].writeToParcel(out, batteryRealtime);
@@ -6183,8 +6208,8 @@
                 pr.println("*** Screen brightness #" + i + ":");
                 mScreenBrightnessTimer[i].logState(pr, "  ");
             }
-            pr.println("*** Input event counter:");
-            mInputEventCounter.logState(pr, "  ");
+            pr.println("*** Interactive timer:");
+            mInteractiveTimer.logState(pr, "  ");
             pr.println("*** Phone timer:");
             mPhoneOnTimer.logState(pr, "  ");
             for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
diff --git a/core/java/com/android/internal/os/BinderInternal.java b/core/java/com/android/internal/os/BinderInternal.java
index f54a3e9..3b0f0f4 100644
--- a/core/java/com/android/internal/os/BinderInternal.java
+++ b/core/java/com/android/internal/os/BinderInternal.java
@@ -16,18 +16,11 @@
 
 package com.android.internal.os;
 
-import android.os.Binder;
 import android.os.IBinder;
 import android.os.SystemClock;
 import android.util.EventLog;
-import android.util.Log;
 
-import java.io.FileDescriptor;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
-import java.lang.reflect.Modifier;
 
 /**
  * Private and debugging Binder APIs.
diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java
index 02bd4ac..86c9fe3 100644
--- a/core/java/com/android/internal/view/BaseIWindow.java
+++ b/core/java/com/android/internal/view/BaseIWindow.java
@@ -57,10 +57,6 @@
     }
 
     @Override
-    public void dispatchScreenState(boolean on) {
-    }
-
-    @Override
     public void windowFocusChanged(boolean hasFocus, boolean touchEnabled) {
     }
 
diff --git a/core/java/com/android/internal/view/RotationPolicy.java b/core/java/com/android/internal/view/RotationPolicy.java
index 70e2bfc..6295314 100644
--- a/core/java/com/android/internal/view/RotationPolicy.java
+++ b/core/java/com/android/internal/view/RotationPolicy.java
@@ -21,7 +21,6 @@
 import android.database.ContentObserver;
 import android.net.Uri;
 import android.os.AsyncTask;
-import android.os.Build;
 import android.os.Handler;
 import android.os.RemoteException;
 import android.os.UserHandle;
@@ -52,7 +51,9 @@
         PackageManager pm = context.getPackageManager();
         return pm.hasSystemFeature(PackageManager.FEATURE_SENSOR_ACCELEROMETER)
                 && pm.hasSystemFeature(PackageManager.FEATURE_SCREEN_PORTRAIT)
-                && pm.hasSystemFeature(PackageManager.FEATURE_SCREEN_LANDSCAPE);
+                && pm.hasSystemFeature(PackageManager.FEATURE_SCREEN_LANDSCAPE)
+                && context.getResources().getBoolean(
+                        com.android.internal.R.bool.config_supportAutoRotation);
     }
 
     /**
@@ -176,6 +177,7 @@
      */
     public static abstract class RotationPolicyListener {
         final ContentObserver mObserver = new ContentObserver(new Handler()) {
+            @Override
             public void onChange(boolean selfChange, Uri uri) {
                 RotationPolicyListener.this.onChange();
             }
diff --git a/core/java/com/android/internal/view/menu/MenuBuilder.java b/core/java/com/android/internal/view/menu/MenuBuilder.java
index 195a00d..5464284 100644
--- a/core/java/com/android/internal/view/menu/MenuBuilder.java
+++ b/core/java/com/android/internal/view/menu/MenuBuilder.java
@@ -392,8 +392,8 @@
     private MenuItem addInternal(int group, int id, int categoryOrder, CharSequence title) {
         final int ordering = getOrdering(categoryOrder);
         
-        final MenuItemImpl item = new MenuItemImpl(this, group, id, categoryOrder,
-                ordering, title, mDefaultShowAsAction);
+        final MenuItemImpl item = createNewMenuItem(group, id, categoryOrder, ordering, title,
+                mDefaultShowAsAction);
 
         if (mCurrentMenuInfo != null) {
             // Pass along the current menu info
@@ -405,7 +405,14 @@
         
         return item;
     }
-    
+
+    // Layoutlib overrides this method to return its custom implementation of MenuItemImpl
+    private MenuItemImpl createNewMenuItem(int group, int id, int categoryOrder, int ordering,
+            CharSequence title, int defaultShowAsAction) {
+        return new MenuItemImpl(this, group, id, categoryOrder, ordering, title,
+                defaultShowAsAction);
+    }
+
     public MenuItem add(CharSequence title) {
         return addInternal(0, 0, 0, title);
     }
diff --git a/core/java/com/android/internal/widget/ActionBarOverlayLayout.java b/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
index 5469b63..c957b67 100644
--- a/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
+++ b/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
@@ -20,6 +20,7 @@
 import android.graphics.drawable.Drawable;
 import android.os.Build;
 import android.view.ViewGroup;
+import android.view.WindowInsets;
 import com.android.internal.app.ActionBarImpl;
 
 import android.content.Context;
@@ -96,7 +97,7 @@
             if (mLastSystemUiVisibility != 0) {
                 int newVis = mLastSystemUiVisibility;
                 onWindowSystemUiVisibilityChanged(newVis);
-                requestFitSystemWindows();
+                requestApplyInsets();
             }
         }
     }
@@ -152,7 +153,7 @@
         }
         if ((diff&SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0) {
             if (mActionBar != null) {
-                requestFitSystemWindows();
+                requestApplyInsets();
             }
         }
     }
@@ -190,19 +191,20 @@
     }
 
     @Override
-    protected boolean fitSystemWindows(Rect insets) {
+    public WindowInsets onApplyWindowInsets(WindowInsets insets) {
         pullChildren();
 
         final int vis = getWindowSystemUiVisibility();
         final boolean stable = (vis & SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0;
+        final Rect systemInsets = insets.getSystemWindowInsets();
 
         // The top and bottom action bars are always within the content area.
-        boolean changed = applyInsets(mActionBarTop, insets, true, true, false, true);
+        boolean changed = applyInsets(mActionBarTop, systemInsets, true, true, false, true);
         if (mActionBarBottom != null) {
-            changed |= applyInsets(mActionBarBottom, insets, true, false, true, true);
+            changed |= applyInsets(mActionBarBottom, systemInsets, true, false, true, true);
         }
 
-        mBaseInnerInsets.set(insets);
+        mBaseInnerInsets.set(systemInsets);
         computeFitSystemWindows(mBaseInnerInsets, mBaseContentInsets);
         if (!mLastBaseContentInsets.equals(mBaseContentInsets)) {
             changed = true;
@@ -215,9 +217,9 @@
 
         // We don't do any more at this point.  To correctly compute the content/inner
         // insets in all cases, we need to know the measured size of the various action
-        // bar elements.  fitSystemWindows() happens before the measure pass, so we can't
+        // bar elements.  onApplyWindowInsets() happens before the measure pass, so we can't
         // do that here.  Instead we will take this up in onMeasure().
-        return true;
+        return WindowInsets.EMPTY;
     }
 
     @Override
@@ -321,7 +323,7 @@
             // the app's fitSystemWindows().  We do this before measuring the content
             // view to keep the same semantics as the normal fitSystemWindows() call.
             mLastInnerInsets.set(mInnerInsets);
-            super.fitSystemWindows(mInnerInsets);
+            mContent.dispatchApplyWindowInsets(new WindowInsets(mInnerInsets));
         }
 
         measureChildWithMargins(mContent, widthMeasureSpec, 0, heightMeasureSpec, 0);
diff --git a/core/java/com/android/internal/widget/SwipeDismissLayout.java b/core/java/com/android/internal/widget/SwipeDismissLayout.java
new file mode 100644
index 0000000..bcfa036
--- /dev/null
+++ b/core/java/com/android/internal/widget/SwipeDismissLayout.java
@@ -0,0 +1,305 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.widget;
+
+import android.animation.TimeInterpolator;
+import android.content.Context;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.VelocityTracker;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.ViewGroup;
+import android.view.animation.AccelerateInterpolator;
+import android.view.animation.DecelerateInterpolator;
+import android.widget.FrameLayout;
+
+/**
+ * Special layout that finishes its activity when swiped away.
+ */
+public class SwipeDismissLayout extends FrameLayout {
+    private static final String TAG = "SwipeDismissLayout";
+
+    private static final float DISMISS_MIN_DRAG_WIDTH_RATIO = .4f;
+
+    public interface OnDismissedListener {
+        void onDismissed(SwipeDismissLayout layout);
+    }
+
+    public interface OnSwipeProgressChangedListener {
+        /**
+         * Called when the layout has been swiped and the position of the window should change.
+         *
+         * @param progress A number in [-1, 1] representing how far to the left
+         * or right the window has been swiped. Negative values are swipes
+         * left, and positives are right.
+         * @param translate A number in [-w, w], where w is the width of the
+         * layout. This is equivalent to progress * layout.getWidth().
+         */
+        void onSwipeProgressChanged(SwipeDismissLayout layout, float progress, float translate);
+
+        void onSwipeCancelled(SwipeDismissLayout layout);
+    }
+
+    // Cached ViewConfiguration and system-wide constant values
+    private int mSlop;
+    private int mMinFlingVelocity;
+    private int mMaxFlingVelocity;
+    private long mAnimationTime;
+    private TimeInterpolator mCancelInterpolator;
+    private TimeInterpolator mDismissInterpolator;
+
+    // Transient properties
+    private int mActiveTouchId;
+    private float mDownX;
+    private float mDownY;
+    private boolean mSwiping;
+    private boolean mDismissed;
+    private boolean mDiscardIntercept;
+    private VelocityTracker mVelocityTracker;
+    private float mTranslationX;
+
+    private OnDismissedListener mDismissedListener;
+    private OnSwipeProgressChangedListener mProgressListener;
+
+    private float mLastX;
+
+    public SwipeDismissLayout(Context context) {
+        super(context);
+        init(context);
+    }
+
+    public SwipeDismissLayout(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        init(context);
+    }
+
+    public SwipeDismissLayout(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+        init(context);
+    }
+
+    private void init(Context context) {
+        ViewConfiguration vc = ViewConfiguration.get(getContext());
+        mSlop = vc.getScaledTouchSlop();
+        mMinFlingVelocity = vc.getScaledMinimumFlingVelocity();
+        mMaxFlingVelocity = vc.getScaledMaximumFlingVelocity();
+        mAnimationTime = getContext().getResources().getInteger(
+                android.R.integer.config_shortAnimTime);
+        mCancelInterpolator = new DecelerateInterpolator(1.5f);
+        mDismissInterpolator = new AccelerateInterpolator(1.5f);
+    }
+
+    public void setOnDismissedListener(OnDismissedListener listener) {
+        mDismissedListener = listener;
+    }
+
+    public void setOnSwipeProgressChangedListener(OnSwipeProgressChangedListener listener) {
+        mProgressListener = listener;
+    }
+
+    @Override
+    public boolean onInterceptTouchEvent(MotionEvent ev) {
+        // offset because the view is translated during swipe
+        ev.offsetLocation(mTranslationX, 0);
+
+        switch (ev.getActionMasked()) {
+            case MotionEvent.ACTION_DOWN:
+                resetMembers();
+                mDownX = ev.getRawX();
+                mDownY = ev.getRawY();
+                mActiveTouchId = ev.getPointerId(0);
+                mVelocityTracker = VelocityTracker.obtain();
+                mVelocityTracker.addMovement(ev);
+                break;
+
+            case MotionEvent.ACTION_POINTER_DOWN:
+                int actionIndex = ev.getActionIndex();
+                mActiveTouchId = ev.getPointerId(actionIndex);
+                break;
+            case MotionEvent.ACTION_POINTER_UP:
+                actionIndex = ev.getActionIndex();
+                int pointerId = ev.getPointerId(actionIndex);
+                if (pointerId == mActiveTouchId) {
+                    // This was our active pointer going up. Choose a new active pointer.
+                    int newActionIndex = actionIndex == 0 ? 1 : 0;
+                    mActiveTouchId = ev.getPointerId(newActionIndex);
+                }
+                break;
+
+            case MotionEvent.ACTION_CANCEL:
+            case MotionEvent.ACTION_UP:
+                resetMembers();
+                break;
+
+            case MotionEvent.ACTION_MOVE:
+                if (mVelocityTracker == null || mDiscardIntercept) {
+                    break;
+                }
+
+                int pointerIndex = ev.findPointerIndex(mActiveTouchId);
+                if (pointerIndex == -1) {
+                    Log.e(TAG, "Invalid pointer index: ignoring.");
+                    mDiscardIntercept = true;
+                    break;
+                }
+                float dx = ev.getRawX() - mDownX;
+                float x = ev.getX(pointerIndex);
+                float y = ev.getY(pointerIndex);
+                if (dx != 0 && canScroll(this, false, dx, x, y)) {
+                    mDiscardIntercept = true;
+                    break;
+                }
+                updateSwiping(ev);
+                break;
+        }
+
+        return !mDiscardIntercept && mSwiping;
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent ev) {
+        if (mVelocityTracker == null) {
+            return super.onTouchEvent(ev);
+        }
+        switch (ev.getActionMasked()) {
+            case MotionEvent.ACTION_UP:
+                updateDismiss(ev);
+                if (mDismissed) {
+                    dismiss();
+                } else if (mSwiping) {
+                    cancel();
+                }
+                resetMembers();
+                break;
+
+            case MotionEvent.ACTION_CANCEL:
+                cancel();
+                resetMembers();
+                break;
+
+            case MotionEvent.ACTION_MOVE:
+                mVelocityTracker.addMovement(ev);
+                mLastX = ev.getRawX();
+                updateSwiping(ev);
+                if (mSwiping) {
+                    setProgress(ev.getRawX() - mDownX);
+                    break;
+                }
+        }
+        return true;
+    }
+
+    private void setProgress(float deltaX) {
+        mTranslationX = deltaX;
+        if (mProgressListener != null) {
+            mProgressListener.onSwipeProgressChanged(this, deltaX / getWidth(), deltaX);
+        }
+    }
+
+    private void dismiss() {
+        if (mDismissedListener != null) {
+            mDismissedListener.onDismissed(this);
+        }
+    }
+
+    protected void cancel() {
+        if (mProgressListener != null) {
+            mProgressListener.onSwipeCancelled(this);
+        }
+    }
+
+    /**
+     * Resets internal members when canceling.
+     */
+    private void resetMembers() {
+        if (mVelocityTracker != null) {
+            mVelocityTracker.recycle();
+        }
+        mVelocityTracker = null;
+        mTranslationX = 0;
+        mDownX = 0;
+        mDownY = 0;
+        mSwiping = false;
+        mDismissed = false;
+        mDiscardIntercept = false;
+    }
+
+    private void updateSwiping(MotionEvent ev) {
+        if (!mSwiping) {
+            float deltaX = ev.getRawX() - mDownX;
+            float deltaY = ev.getRawY() - mDownY;
+            if ((deltaX * deltaX) + (deltaY * deltaY) > mSlop * mSlop) {
+                mSwiping = deltaX > mSlop * 2 && Math.abs(deltaY) < mSlop * 2;
+            } else {
+                mSwiping = false;
+            }
+        }
+    }
+
+    private void updateDismiss(MotionEvent ev) {
+        float deltaX = ev.getRawX() - mDownX;
+        if (!mDismissed) {
+            mVelocityTracker.addMovement(ev);
+            mVelocityTracker.computeCurrentVelocity(1000);
+
+            if (deltaX > (getWidth() * DISMISS_MIN_DRAG_WIDTH_RATIO) &&
+                    ev.getRawX() >= mLastX) {
+                mDismissed = true;
+            }
+        }
+        // Check if the user tried to undo this.
+        if (mDismissed && mSwiping) {
+            // Check if the user's finger is actually back
+            if (deltaX < (getWidth() * DISMISS_MIN_DRAG_WIDTH_RATIO)) {
+                mDismissed = false;
+            }
+        }
+    }
+
+    /**
+     * Tests scrollability within child views of v in the direction of dx.
+     *
+     * @param v View to test for horizontal scrollability
+     * @param checkV Whether the view v passed should itself be checked for scrollability (true),
+     *               or just its children (false).
+     * @param dx Delta scrolled in pixels. Only the sign of this is used.
+     * @param x X coordinate of the active touch point
+     * @param y Y coordinate of the active touch point
+     * @return true if child views of v can be scrolled by delta of dx.
+     */
+    protected boolean canScroll(View v, boolean checkV, float dx, float x, float y) {
+        if (v instanceof ViewGroup) {
+            final ViewGroup group = (ViewGroup) v;
+            final int scrollX = v.getScrollX();
+            final int scrollY = v.getScrollY();
+            final int count = group.getChildCount();
+            for (int i = count - 1; i >= 0; i--) {
+                final View child = group.getChildAt(i);
+                if (x + scrollX >= child.getLeft() && x + scrollX < child.getRight() &&
+                        y + scrollY >= child.getTop() && y + scrollY < child.getBottom() &&
+                        canScroll(child, true, dx, x + scrollX - child.getLeft(),
+                                y + scrollY - child.getTop())) {
+                    return true;
+                }
+            }
+        }
+
+        return checkV && v.canScrollHorizontally((int) -dx);
+    }
+}
diff --git a/core/java/com/android/server/LocalServices.java b/core/java/com/android/server/LocalServices.java
new file mode 100644
index 0000000..25dcb30
--- /dev/null
+++ b/core/java/com/android/server/LocalServices.java
@@ -0,0 +1,60 @@
+/*
+ * 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;
+
+import android.util.ArrayMap;
+
+/**
+ * This class is used in a similar way as ServiceManager, except the services registered here
+ * are not Binder objects and are only available in the same process.
+ *
+ * Once all services are converted to the SystemService interface, this class can be absorbed
+ * into SystemServiceManager.
+ *
+ * {@hide}
+ */
+public final class LocalServices {
+    private LocalServices() {}
+
+    private static final ArrayMap<Class<?>, Object> sLocalServiceObjects =
+            new ArrayMap<Class<?>, Object>();
+
+    /**
+     * Returns a local service instance that implements the specified interface.
+     *
+     * @param type The type of service.
+     * @return The service object.
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> T getService(Class<T> type) {
+        synchronized (sLocalServiceObjects) {
+            return (T) sLocalServiceObjects.get(type);
+        }
+    }
+
+    /**
+     * Adds a service instance of the specified interface to the global registry of local services.
+     */
+    public static <T> void addService(Class<T> type, T service) {
+        synchronized (sLocalServiceObjects) {
+            if (sLocalServiceObjects.containsKey(type)) {
+                throw new IllegalStateException("Overriding service registration");
+            }
+            sLocalServiceObjects.put(type, service);
+        }
+    }
+}
diff --git a/core/java/com/android/server/SystemService.java b/core/java/com/android/server/SystemService.java
new file mode 100644
index 0000000..e374563
--- /dev/null
+++ b/core/java/com/android/server/SystemService.java
@@ -0,0 +1,218 @@
+/*
+ * 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;
+
+import android.content.Context;
+import android.os.IBinder;
+import android.os.ServiceManager;
+
+/**
+ * The base class for services running in the system process. Override and implement
+ * the lifecycle event callback methods as needed.
+ * <p>
+ * The lifecycle of a SystemService:
+ * </p><ul>
+ * <li>The constructor is called and provided with the system {@link Context}
+ * to initialize the system service.
+ * <li>{@link #onStart()} is called to get the service running.  The service should
+ * publish its binder interface at this point using
+ * {@link #publishBinderService(String, IBinder)}.  It may also publish additional
+ * local interfaces that other services within the system server may use to access
+ * privileged internal functions.
+ * <li>Then {@link #onBootPhase(int)} is called as many times as there are boot phases
+ * until {@link #PHASE_BOOT_COMPLETE} is sent, which is the last boot phase. Each phase
+ * is an opportunity to do special work, like acquiring optional service dependencies,
+ * waiting to see if SafeMode is enabled, or registering with a service that gets
+ * started after this one.
+ * </ul><p>
+ * NOTE: All lifecycle methods are called from the system server's main looper thread.
+ * </p>
+ *
+ * {@hide}
+ */
+public abstract class SystemService {
+    /*
+     * Boot Phases
+     */
+    public static final int PHASE_WAIT_FOR_DEFAULT_DISPLAY = 100; // maybe should be a dependency?
+
+    /**
+     * After receiving this boot phase, services can obtain lock settings data.
+     */
+    public static final int PHASE_LOCK_SETTINGS_READY = 480;
+
+    /**
+     * After receiving this boot phase, services can safely call into core system services
+     * such as the PowerManager or PackageManager.
+     */
+    public static final int PHASE_SYSTEM_SERVICES_READY = 500;
+
+    /**
+     * After receiving this boot phase, services can broadcast Intents.
+     */
+    public static final int PHASE_ACTIVITY_MANAGER_READY = 550;
+
+    /**
+     * After receiving this boot phase, services can start/bind to third party apps.
+     * Apps will be able to make Binder calls into services at this point.
+     */
+    public static final int PHASE_THIRD_PARTY_APPS_CAN_START = 600;
+
+    /**
+     * After receiving this boot phase, services must have finished all boot-related work.
+     */
+    public static final int PHASE_BOOT_COMPLETE = 1000;
+
+    private final Context mContext;
+
+    /**
+     * Initializes the system service.
+     * <p>
+     * Subclasses must define a single argument constructor that accepts the context
+     * and passes it to super.
+     * </p>
+     *
+     * @param context The system server context.
+     */
+    public SystemService(Context context) {
+        mContext = context;
+    }
+
+    /**
+     * Gets the system context.
+     */
+    public final Context getContext() {
+        return mContext;
+    }
+
+    /**
+     * Returns true if the system is running in safe mode.
+     * TODO: we should define in which phase this becomes valid
+     */
+    public final boolean isSafeMode() {
+        return getManager().isSafeMode();
+    }
+
+    /**
+     * Called when the dependencies listed in the @Service class-annotation are available
+     * and after the chosen start phase.
+     * When this method returns, the service should be published.
+     */
+    public abstract void onStart();
+
+    /**
+     * Called on each phase of the boot process. Phases before the service's start phase
+     * (as defined in the @Service annotation) are never received.
+     *
+     * @param phase The current boot phase.
+     */
+    public void onBootPhase(int phase) {}
+
+    /**
+     * Publish the service so it is accessible to other services and apps.
+     */
+    protected final void publishBinderService(String name, IBinder service) {
+        publishBinderService(name, service, false);
+    }
+
+    /**
+     * Publish the service so it is accessible to other services and apps.
+     */
+    protected final void publishBinderService(String name, IBinder service,
+            boolean allowIsolated) {
+        ServiceManager.addService(name, service, allowIsolated);
+    }
+
+    /**
+     * Get a binder service by its name.
+     */
+    protected final IBinder getBinderService(String name) {
+        return ServiceManager.getService(name);
+    }
+
+    /**
+     * Publish the service so it is only accessible to the system process.
+     */
+    protected final <T> void publishLocalService(Class<T> type, T service) {
+        LocalServices.addService(type, service);
+    }
+
+    /**
+     * Get a local service by interface.
+     */
+    protected final <T> T getLocalService(Class<T> type) {
+        return LocalServices.getService(type);
+    }
+
+    private SystemServiceManager getManager() {
+        return LocalServices.getService(SystemServiceManager.class);
+    }
+
+//    /**
+//     * Called when a new user has been created. If your service deals with multiple users, this
+//     * method should be overridden.
+//     *
+//     * @param userHandle The user that was created.
+//     */
+//    public void onUserCreated(int userHandle) {
+//    }
+//
+//    /**
+//     * Called when an existing user has started a new session. If your service deals with multiple
+//     * users, this method should be overridden.
+//     *
+//     * @param userHandle The user who started a new session.
+//     */
+//    public void onUserStarted(int userHandle) {
+//    }
+//
+//    /**
+//     * Called when a background user session has entered the foreground. If your service deals with
+//     * multiple users, this method should be overridden.
+//     *
+//     * @param userHandle The user who's session entered the foreground.
+//     */
+//    public void onUserForeground(int userHandle) {
+//    }
+//
+//    /**
+//     * Called when a foreground user session has entered the background. If your service deals with
+//     * multiple users, this method should be overridden;
+//     *
+//     * @param userHandle The user who's session entered the background.
+//     */
+//    public void onUserBackground(int userHandle) {
+//    }
+//
+//    /**
+//     * Called when a user's active session has stopped. If your service deals with multiple users,
+//     * this method should be overridden.
+//     *
+//     * @param userHandle The user who's session has stopped.
+//     */
+//    public void onUserStopped(int userHandle) {
+//    }
+//
+//    /**
+//     * Called when a user has been removed from the system. If your service deals with multiple
+//     * users, this method should be overridden.
+//     *
+//     * @param userHandle The user who has been removed.
+//     */
+//    public void onUserRemoved(int userHandle) {
+//    }
+}
diff --git a/core/java/com/android/server/SystemServiceManager.java b/core/java/com/android/server/SystemServiceManager.java
new file mode 100644
index 0000000..eb8df0e
--- /dev/null
+++ b/core/java/com/android/server/SystemServiceManager.java
@@ -0,0 +1,164 @@
+/*
+ * 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;
+
+import android.content.Context;
+import android.util.Slog;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+
+/**
+ * Manages creating, starting, and other lifecycle events of
+ * {@link com.android.server.SystemService system services}.
+ *
+ * {@hide}
+ */
+public class SystemServiceManager {
+    private static final String TAG = "SystemServiceManager";
+
+    private final Context mContext;
+    private boolean mSafeMode;
+
+    // Services that should receive lifecycle events.
+    private final ArrayList<SystemService> mServices = new ArrayList<SystemService>();
+
+    private int mCurrentPhase = -1;
+
+    public SystemServiceManager(Context context) {
+        mContext = context;
+    }
+
+    /**
+     * Starts a service by class name.
+     *
+     * @return The service instance.
+     */
+    @SuppressWarnings("unchecked")
+    public SystemService startService(String className) throws ClassNotFoundException {
+        return startService((Class<SystemService>) Class.forName(className));
+    }
+
+    /**
+     * Creates and starts a system service. The class must be a subclass of
+     * {@link com.android.server.SystemService}.
+     *
+     * @param serviceClass A Java class that implements the SystemService interface.
+     * @return The service instance, never null.
+     * @throws RuntimeException if the service fails to start.
+     */
+    @SuppressWarnings("unchecked")
+    public <T extends SystemService> T startService(Class<T> serviceClass) {
+        final String name = serviceClass.getName();
+        Slog.i(TAG, "Starting " + name);
+
+        // Create the service.
+        if (!SystemService.class.isAssignableFrom(serviceClass)) {
+            throw new RuntimeException("Failed to create " + name
+                    + ": service must extend " + SystemService.class.getName());
+        }
+        final T service;
+        try {
+            Constructor<T> constructor = serviceClass.getConstructor(Context.class);
+            service = constructor.newInstance(mContext);
+        } catch (InstantiationException ex) {
+            throw new RuntimeException("Failed to create service " + name
+                    + ": service could not be instantiated", ex);
+        } catch (IllegalAccessException ex) {
+            throw new RuntimeException("Failed to create service " + name
+                    + ": service must have a public constructor with a Context argument", ex);
+        } catch (NoSuchMethodException ex) {
+            throw new RuntimeException("Failed to create service " + name
+                    + ": service must have a public constructor with a Context argument", ex);
+        } catch (InvocationTargetException ex) {
+            throw new RuntimeException("Failed to create service " + name
+                    + ": service constructor threw an exception", ex);
+        }
+
+        // Register it.
+        mServices.add(service);
+
+        // Start it.
+        try {
+            service.onStart();
+        } catch (RuntimeException ex) {
+            throw new RuntimeException("Failed to start service " + name
+                    + ": onStart threw an exception", ex);
+        }
+        return service;
+    }
+
+    /**
+     * Starts the specified boot phase for all system services that have been started up to
+     * this point.
+     *
+     * @param phase The boot phase to start.
+     */
+    public void startBootPhase(final int phase) {
+        if (phase <= mCurrentPhase) {
+            throw new IllegalArgumentException("Next phase must be larger than previous");
+        }
+        mCurrentPhase = phase;
+
+        Slog.i(TAG, "Starting phase " + mCurrentPhase);
+
+        final int serviceLen = mServices.size();
+        for (int i = 0; i < serviceLen; i++) {
+            final SystemService service = mServices.get(i);
+            try {
+                service.onBootPhase(mCurrentPhase);
+            } catch (Exception ex) {
+                throw new RuntimeException("Failed to boot service "
+                        + service.getClass().getName()
+                        + ": onBootPhase threw an exception during phase "
+                        + mCurrentPhase, ex);
+            }
+        }
+    }
+
+    /** Sets the safe mode flag for services to query. */
+    public void setSafeMode(boolean safeMode) {
+        mSafeMode = safeMode;
+    }
+
+    /**
+     * Returns whether we are booting into safe mode.
+     * @return safe mode flag
+     */
+    public boolean isSafeMode() {
+        return mSafeMode;
+    }
+
+    /**
+     * Outputs the state of this manager to the System log.
+     */
+    public void dump() {
+        StringBuilder builder = new StringBuilder();
+        builder.append("Current phase: ").append(mCurrentPhase).append("\n");
+        builder.append("Services:\n");
+        final int startedLen = mServices.size();
+        for (int i = 0; i < startedLen; i++) {
+            final SystemService service = mServices.get(i);
+            builder.append("\t")
+                    .append(service.getClass().getSimpleName())
+                    .append("\n");
+        }
+
+        Slog.e(TAG, builder.toString());
+    }
+}
diff --git a/core/jni/android_hardware_SensorManager.cpp b/core/jni/android_hardware_SensorManager.cpp
index 24e0b0a..7a4728d 100644
--- a/core/jni/android_hardware_SensorManager.cpp
+++ b/core/jni/android_hardware_SensorManager.cpp
@@ -49,6 +49,8 @@
     jfieldID    minDelay;
     jfieldID    fifoReservedEventCount;
     jfieldID    fifoMaxEventCount;
+    jfieldID    stringType;
+    jfieldID    requiredPermission;
 } gSensorOffsets;
 
 
@@ -73,6 +75,9 @@
     sensorOffsets.fifoReservedEventCount =
             _env->GetFieldID(sensorClass, "mFifoReservedEventCount",  "I");
     sensorOffsets.fifoMaxEventCount = _env->GetFieldID(sensorClass, "mFifoMaxEventCount",  "I");
+    sensorOffsets.stringType = _env->GetFieldID(sensorClass, "mStringType", "Ljava/lang/String;");
+    sensorOffsets.requiredPermission = _env->GetFieldID(sensorClass, "mRequiredPermission",
+                                                        "Ljava/lang/String;");
 }
 
 static jint
@@ -89,6 +94,8 @@
     const SensorOffsets& sensorOffsets(gSensorOffsets);
     jstring name = env->NewStringUTF(list->getName().string());
     jstring vendor = env->NewStringUTF(list->getVendor().string());
+    jstring stringType = env->NewStringUTF(list->getStringType().string());
+    jstring requiredPermission = env->NewStringUTF(list->getRequiredPermission().string());
     env->SetObjectField(sensor, sensorOffsets.name,      name);
     env->SetObjectField(sensor, sensorOffsets.vendor,    vendor);
     env->SetIntField(sensor, sensorOffsets.version,      list->getVersion());
@@ -100,7 +107,11 @@
     env->SetIntField(sensor, sensorOffsets.minDelay,     list->getMinDelay());
     env->SetIntField(sensor, sensorOffsets.fifoReservedEventCount,
                      list->getFifoReservedEventCount());
-    env->SetIntField(sensor, sensorOffsets.fifoMaxEventCount, list->getFifoMaxEventCount());
+    env->SetIntField(sensor, sensorOffsets.fifoMaxEventCount,
+                     list->getFifoMaxEventCount());
+    env->SetObjectField(sensor, sensorOffsets.stringType, stringType);
+    env->SetObjectField(sensor, sensorOffsets.requiredPermission,
+                        requiredPermission);
     next++;
     return size_t(next) < count ? next : 0;
 }
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index 31876ce..01f4d3a 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -345,23 +345,6 @@
     return pri;
 }
 
-jboolean android_os_Process_setOomAdj(JNIEnv* env, jobject clazz,
-                                      jint pid, jint adj)
-{
-#ifdef HAVE_OOM_ADJ
-    char text[64];
-    sprintf(text, "/proc/%d/oom_adj", pid);
-    int fd = open(text, O_WRONLY);
-    if (fd >= 0) {
-        sprintf(text, "%d", adj);
-        write(fd, text, strlen(text));
-        close(fd);
-    }
-    return true;
-#endif
-    return false;
-}
-
 jboolean android_os_Process_setSwappiness(JNIEnv *env, jobject clazz,
                                           jint pid, jboolean is_increased)
 {
@@ -1026,7 +1009,6 @@
     {"setThreadGroup",      "(II)V", (void*)android_os_Process_setThreadGroup},
     {"setProcessGroup",     "(II)V", (void*)android_os_Process_setProcessGroup},
     {"getProcessGroup",     "(I)I", (void*)android_os_Process_getProcessGroup},
-    {"setOomAdj",   "(II)Z", (void*)android_os_Process_setOomAdj},
     {"setSwappiness",   "(IZ)Z", (void*)android_os_Process_setSwappiness},
     {"setArgV0",    "(Ljava/lang/String;)V", (void*)android_os_Process_setArgV0},
     {"setUid", "(I)I", (void*)android_os_Process_setUid},
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 8ec2d64..3c40d43 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -481,6 +481,13 @@
         android:label="@string/permlab_writeProfile"
         android:description="@string/permdesc_writeProfile" />
 
+    <!-- Allows an application to access data from sensors that the user uses to
+         measure what is happening inside his/her body, such as heart rate. -->
+    <permission android:name="android.permission.BODY_SENSORS"
+        android:permissionGroup="android.permission-group.PERSONAL_INFO"
+        android:label="@string/permlab_bodySensors"
+        android:description="@string/permdesc_bodySensors" />
+
     <!-- =============================================================== -->
     <!-- Permissions for accessing the device calendar                   -->
     <!-- =============================================================== -->
@@ -682,6 +689,12 @@
         android:label="@string/permlab_installLocationProvider"
         android:description="@string/permdesc_installLocationProvider" />
 
+    <!-- Allows HDMI-CEC service to access device and configuration files.
+         @hide This should only be used by HDMI-CEC service.
+    -->
+    <permission android:name="android.permission.HDMI_CEC"
+        android:protectionLevel="signatureOrSystem" />
+
     <!-- Allows an application to use location features in hardware,
          such as the geofencing api.
          <p>Not for use by third-party applications. -->
@@ -1056,9 +1069,8 @@
         android:permissionGroupFlags="personalInfo"
         android:priority="370" />
 
-    <!-- Allows an application to see the number being dialed during an outgoing
-         call with the option to redirect the call to a different number or
-         abort the call altogether. -->
+    <!-- Allows an application to modify or abort outgoing
+         calls. -->
     <permission android:name="android.permission.PROCESS_OUTGOING_CALLS"
         android:permissionGroup="android.permission-group.PHONE_CALLS"
         android:protectionLevel="dangerous"
@@ -1297,7 +1309,7 @@
     <!-- @hide Allows an application to create/manage/remove stacks -->
     <permission android:name="android.permission.MANAGE_ACTIVITY_STACKS"
         android:permissionGroup="android.permission-group.APP_INFO"
-        android:protectionLevel="signature"
+        android:protectionLevel="signature|system"
         android:label="@string/permlab_manageActivityStacks"
         android:description="@string/permdesc_manageActivityStacks" />
 
@@ -2365,13 +2377,13 @@
          @hide -->
     <permission android:name="android.permission.READ_DREAM_STATE"
         android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
-        android:protectionLevel="signature" />
+        android:protectionLevel="signature|system" />
 
     <!-- Allows applications to write dream settings, and start or stop dreaming.
          @hide -->
     <permission android:name="android.permission.WRITE_DREAM_STATE"
         android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
-        android:protectionLevel="signature" />
+        android:protectionLevel="signature|system" />
 
     <!-- Allow an application to read and write the cache partition.
          @hide -->
@@ -2522,6 +2534,13 @@
         android:description="@string/permdesc_accessNetworkConditions"
         android:protectionLevel="signature|system" />
 
+    <!-- Allows an application to provision and access DRM certificates
+         @hide This is not a third-party API (intended for system apps). -->
+    <permission android:name="android.permission.ACCESS_DRM_CERTIFICATES"
+        android:label="@string/permlab_accessDrmCertificates"
+        android:description="@string/permdesc_accessDrmCertificates"
+        android:protectionLevel="signature|system" />
+
     <!-- The system process is explicitly the only one allowed to launch the
          confirmation UI for full backup/restore -->
     <uses-permission android:name="android.permission.CONFIRM_FULL_BACKUP"/>
@@ -2531,7 +2550,7 @@
                  android:hasCode="false"
                  android:label="@string/android_system_label"
                  android:allowClearUserData="false"
-                 android:backupAgent="com.android.server.SystemBackupAgent"
+                 android:backupAgent="com.android.server.backup.SystemBackupAgent"
                  android:killAfterRestore="false"
                  android:icon="@drawable/ic_launcher_android"
                  android:supportsRtl="true">
diff --git a/core/res/res/anim/swipe_window_enter.xml b/core/res/res/anim/swipe_window_enter.xml
new file mode 100644
index 0000000..e1617e2
--- /dev/null
+++ b/core/res/res/anim/swipe_window_enter.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+        android:interpolator="@interpolator/decelerate_quad" >
+    <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
+        android:fillEnabled="true" android:fillBefore="true"
+        android:fillAfter="true"
+        android:duration="@android:integer/config_activityDefaultDur" />
+</set>
diff --git a/core/res/res/anim/swipe_window_exit.xml b/core/res/res/anim/swipe_window_exit.xml
new file mode 100644
index 0000000..ed0c5d3
--- /dev/null
+++ b/core/res/res/anim/swipe_window_exit.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+        android:interpolator="@interpolator/decelerate_quad" >
+    <translate android:fromXDelta="0%" android:toXDelta="100%"
+        android:fillEnabled="true" android:fillBefore="true"
+        android:fillAfter="true"
+        android:duration="400" />
+</set>
diff --git a/core/res/res/drawable-hdpi/ic_settings.png b/core/res/res/drawable-hdpi/ic_settings.png
new file mode 100644
index 0000000..cfa539f
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_settings.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_settings.png b/core/res/res/drawable-mdpi/ic_settings.png
new file mode 100644
index 0000000..e6237eb
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_settings.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_settings.png b/core/res/res/drawable-xhdpi/ic_settings.png
new file mode 100644
index 0000000..208089d
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_settings.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_settings.png b/core/res/res/drawable-xxhdpi/ic_settings.png
new file mode 100644
index 0000000..452942e
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_settings.png
Binary files differ
diff --git a/core/res/res/layout/alert_dialog_micro.xml b/core/res/res/layout/alert_dialog_micro.xml
new file mode 100644
index 0000000..abdbd16
--- /dev/null
+++ b/core/res/res/layout/alert_dialog_micro.xml
@@ -0,0 +1,140 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2014 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/parentPanel"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="@android:color/white"
+    android:layout_gravity="center"
+    android:orientation="vertical">
+
+    <LinearLayout android:id="@+id/topPanel"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical">
+        <View android:id="@+id/titleDividerTop"
+            android:layout_width="match_parent"
+            android:layout_height="2dip"
+            android:visibility="gone"
+            android:background="@android:color/holo_blue_light" />
+        <LinearLayout android:id="@+id/title_template"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal"
+            android:gravity="center_vertical|start"
+            android:minHeight="@dimen/alert_dialog_title_height"
+            android:layout_marginStart="16dip"
+            android:layout_marginEnd="16dip">
+            <ImageView android:id="@+id/icon"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:paddingEnd="8dip"
+                android:src="@null" />
+            <com.android.internal.widget.DialogTitle android:id="@+id/alertTitle"
+                style="?android:attr/windowTitleStyle"
+                android:singleLine="true"
+                android:ellipsize="end"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:textAlignment="viewStart" />
+        </LinearLayout>
+        <View android:id="@+id/titleDivider"
+            android:layout_width="match_parent"
+            android:layout_height="2dip"
+            android:visibility="gone"
+            android:background="@android:color/holo_blue_light" />
+        <!-- If the client uses a customTitle, it will be added here. -->
+    </LinearLayout>
+
+    <LinearLayout android:id="@+id/contentPanel"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:orientation="vertical"
+        android:minHeight="64dp">
+        <ScrollView android:id="@+id/scrollView"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:clipToPadding="false">
+            <TextView android:id="@+id/message"
+                style="?android:attr/textAppearanceMedium"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:paddingStart="16dip"
+                android:paddingEnd="16dip"
+                android:paddingTop="8dip"
+                android:paddingBottom="8dip"/>
+        </ScrollView>
+    </LinearLayout>
+
+    <FrameLayout android:id="@+id/customPanel"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:minHeight="64dp">
+        <FrameLayout android:id="@+android:id/custom"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content" />
+    </FrameLayout>
+
+    <LinearLayout android:id="@+id/buttonPanel"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:minHeight="@dimen/alert_dialog_button_bar_height"
+        android:orientation="vertical"
+        android:divider="?android:attr/dividerHorizontal"
+        android:showDividers="beginning"
+        android:dividerPadding="0dip">
+        <LinearLayout
+            style="?android:attr/buttonBarStyle"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal"
+            android:layoutDirection="locale"
+            android:measureWithLargestChild="true">
+            <Button android:id="@+id/button2"
+                android:layout_width="wrap_content"
+                android:layout_gravity="start"
+                android:layout_weight="1"
+                android:maxLines="2"
+                style="?android:attr/buttonBarButtonStyle"
+                android:textSize="14sp"
+                android:minHeight="@dimen/alert_dialog_button_bar_height"
+                android:layout_height="wrap_content" />
+            <Button android:id="@+id/button3"
+                android:layout_width="wrap_content"
+                android:layout_gravity="center_horizontal"
+                android:layout_weight="1"
+                android:maxLines="2"
+                style="?android:attr/buttonBarButtonStyle"
+                android:textSize="14sp"
+                android:minHeight="@dimen/alert_dialog_button_bar_height"
+                android:layout_height="wrap_content" />
+            <Button android:id="@+id/button1"
+                android:layout_width="wrap_content"
+                android:layout_gravity="end"
+                android:layout_weight="1"
+                android:maxLines="2"
+                android:minHeight="@dimen/alert_dialog_button_bar_height"
+                style="?android:attr/buttonBarButtonStyle"
+                android:textSize="14sp"
+                android:layout_height="wrap_content" />
+        </LinearLayout>
+     </LinearLayout>
+</LinearLayout>
diff --git a/core/res/res/layout/number_picker_with_selector_wheel_micro.xml b/core/res/res/layout/number_picker_with_selector_wheel_micro.xml
new file mode 100644
index 0000000..a1c0921
--- /dev/null
+++ b/core/res/res/layout/number_picker_with_selector_wheel_micro.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2012, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <view class="android.widget.NumberPicker$CustomEditText"
+        android:textAppearance="?android:attr/textAppearanceLarge"
+        android:id="@+id/numberpicker_input"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:gravity="center"
+        android:singleLine="true"
+        android:background="@null" />
+
+</merge>
diff --git a/core/res/res/layout/screen_swipe_dismiss.xml b/core/res/res/layout/screen_swipe_dismiss.xml
new file mode 100644
index 0000000..90e970fe
--- /dev/null
+++ b/core/res/res/layout/screen_swipe_dismiss.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!--
+This is a layout for a window whose resident activity is finished when swiped away.
+-->
+
+<com.android.internal.widget.SwipeDismissLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@android:id/content"
+    android:fitsSystemWindows="true"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    />
diff --git a/core/res/res/values-watch/config.xml b/core/res/res/values-watch/config.xml
new file mode 100644
index 0000000..8d82a17
--- /dev/null
+++ b/core/res/res/values-watch/config.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for watch products.  Do not translate. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Only show settings item due to smaller real estate. -->
+    <string-array translatable="false" name="config_globalActionsList">
+        <item>settings</item>
+    </string-array>
+
+    <!-- Base "touch slop" value used by ViewConfiguration as a
+         movement threshold where scrolling should begin. -->
+    <dimen name="config_viewConfigurationTouchSlop">4dp</dimen>
+
+    <!-- Minimum velocity to initiate a fling, as measured in dips per second. -->
+    <dimen name="config_viewMinFlingVelocity">500dp</dimen>
+
+    <!-- Maximum velocity to initiate a fling, as measured in dips per second. -->
+    <dimen name="config_viewMaxFlingVelocity">8000dp</dimen>
+
+</resources>
diff --git a/core/res/res/values-watch/themes.xml b/core/res/res/values-watch/themes.xml
new file mode 100644
index 0000000..9447d9cb
--- /dev/null
+++ b/core/res/res/values-watch/themes.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<resources>
+    <style name="Theme.Dialog.Alert" parent="Theme.Micro.Dialog.Alert" />
+    <style name="Theme.Dialog.AppError" parent="Theme.Micro.Dialog.AppError" />
+    <style name="Theme.Holo.Dialog.Alert" parent="Theme.Micro.Dialog.Alert" />
+    <style name="Theme.Holo.Light.Dialog.Alert" parent="Theme.Micro.Dialog.Alert" />
+</resources>
diff --git a/core/res/res/values-watch/themes_device_defaults.xml b/core/res/res/values-watch/themes_device_defaults.xml
new file mode 100644
index 0000000..705143c
--- /dev/null
+++ b/core/res/res/values-watch/themes_device_defaults.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<resources>
+    <style name="Theme.DeviceDefault" parent="Theme.Micro" />
+    <style name="Theme.DeviceDefault.NoActionBar" parent="Theme.Micro" />
+    <style name="Theme.DeviceDefault.Dialog" parent="Theme.Micro.Dialog" />
+    <style name="Theme.DeviceDefault.Dialog.Alert" parent="Theme.Micro.Dialog.Alert" />
+    <style name="Theme.DeviceDefault.Light" parent="Theme.Micro.Light" />
+    <style name="Theme.DeviceDefault.Light.NoActionBar" parent="Theme.Micro.Light" />
+    <style name="Theme.DeviceDefault.Light.DarkActionBar" parent="Theme.Micro.Light" />
+    <style name="Theme.DeviceDefault.Light.Dialog" parent="Theme.Micro.Dialog" />
+    <style name="Theme.DeviceDefault.Light.Dialog.Alert" parent="Theme.Micro.Dialog.Alert" />
+
+</resources>
+
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 42e3b50..91d502b 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -447,6 +447,10 @@
              to {@link android.view.WindowManager.LayoutParams#FLAG_TRANSLUCENT_NAVIGATION}. -->
         <attr name="windowTranslucentNavigation" format="boolean" />
 
+        <!-- Flag to indicate that a window can be swiped away to be dismissed.
+             Corresponds to {@link android.view.Window#FEATURE_SWIPE_TO_DISMISS} -->
+        <attr name="windowSwipeToDismiss" format="boolean" />
+
         <!-- ============ -->
         <!-- Alert Dialog styles -->
         <!-- ============ -->
@@ -1567,6 +1571,8 @@
         <enum name="KEYCODE_BRIGHTNESS_DOWN" value="220" />
         <enum name="KEYCODE_BRIGHTNESS_UP" value="221" />
         <enum name="KEYCODE_MEDIA_AUDIO_TRACK" value="222" />
+        <enum name="KEYCODE_MEDIA_SLEEP" value="223" />
+        <enum name="KEYCODE_MEDIA_WAKEUP" value="224" />
     </attr>
 
     <!-- ***************************************************************** -->
@@ -1604,6 +1610,7 @@
         <attr name="windowCloseOnTouchOutside" />
         <attr name="windowTranslucentStatus" />
         <attr name="windowTranslucentNavigation" />
+        <attr name="windowSwipeToDismiss" />
         <!-- The minimum width the window is allowed to be, along the major
              axis of the screen.  That is, when in landscape.  Can be either
              an absolute dimension or a fraction of the screen size in that
@@ -1632,6 +1639,7 @@
              that is, when in portrait. Can be either an absolute dimension
              or a fraction of the screen size in that dimension. -->
         <attr name="windowFixedHeightMajor" format="dimension|fraction" />
+        <attr name="windowOutsetBottom" format="dimension" />
     </declare-styleable>
 
     <!-- The set of attributes that describe a AlertDialog's theme. -->
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 4647413..9b3f2bf 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -62,6 +62,21 @@
          a reference to a Drawable resource containing the image definition. -->
     <attr name="icon" format="reference" />
 
+    <!-- @hide A Drawable resource providing an extended graphical banner for its
+         associated item. Use with the application tag (to supply a default
+         banner for all application activities), or with the activity, tag to
+         supply a banner for a specific activity.
+
+         <p>The given banner will be used to display to the user a graphical
+         representation of an activity in the Leanback application launcher.
+         Since banners are displayed only in the Leanback launcher, they should
+         only be used with activities (and applications) that support Leanback
+         mode. These are activities that handle Intents of category
+         {@link android.content.Intent#CATEGORY_LEANBACK_LAUNCHER
+         Intent.CATEGORY_LEANBACK_LAUNCHER}.
+         <p>This must be a reference to a Drawable resource containing the image definition. -->
+    <attr name="banner" format="reference" />
+
     <!-- A Drawable resource providing an extended graphical logo for its
          associated item. Use with the application tag (to supply a default
          logo for all application components), or with the activity, receiver,
@@ -297,6 +312,12 @@
          content providers. -->
     <attr name="exported" format="boolean" />
 
+    <!-- @hide A boolean flag used to indicate if an application is a Game or not.
+         <p>This information can be used by the system to group together
+         applications that are classified as games, and display them separately
+         from the other applications. -->
+    <attr name="isGame" format="boolean" />
+
     <!-- If set to true, a single instance of this component will run for
          all users.  That instance will run as user 0, the default/primary
          user.  When the app running is in processes for other users and interacts
@@ -714,7 +735,14 @@
              selected a new global font size. -->
         <flag name="fontScale" value="0x40000000" />
     </attr>
-    
+
+    <!-- Indicate that the activity can be launched as the embedded child of another
+         activity. Particularly in the case where the child lives in a container
+         such as a Display owned by another activity.
+
+         <p>The default value of this attribute is <code>false</code>. -->
+    <attr name="allowEmbedded" format="boolean" />
+
     <!-- Descriptive text for the associated data. -->
     <attr name="description" format="reference" />
     
@@ -888,6 +916,8 @@
         <attr name="theme" />
         <attr name="label" />
         <attr name="icon" />
+        <!-- @hide -->
+        <attr name="banner" />
         <attr name="logo" />
         <attr name="description" />
         <attr name="permission" />
@@ -951,6 +981,8 @@
              any accounts. The type should correspond to the account authenticator type, such as
              "com.google". -->
         <attr name="requiredAccountType" format="string"/>
+        <!-- @hide -->
+        <attr name="isGame" />
     </declare-styleable>
     
     <!-- The <code>permission</code> tag declares a security permission that can be
@@ -970,6 +1002,8 @@
         <attr name="name" />
         <attr name="label" />
         <attr name="icon" />
+        <!-- @hide -->
+        <attr name="banner" />
         <attr name="logo" />
         <attr name="permissionGroup" />
         <attr name="description" />
@@ -996,6 +1030,8 @@
         <attr name="name" />
         <attr name="label" />
         <attr name="icon" />
+        <!-- @hide -->
+        <attr name="banner" />
         <attr name="logo" />
         <attr name="description" />
         <attr name="permissionGroupFlags" />
@@ -1028,6 +1064,8 @@
         <attr name="name" />
         <attr name="label" />
         <attr name="icon" />
+        <!-- @hide -->
+        <attr name="banner" />
         <attr name="logo" />
     </declare-styleable>
     
@@ -1294,6 +1332,8 @@
         <attr name="label" />
         <attr name="description" />
         <attr name="icon" />
+        <!-- @hide -->
+        <attr name="banner" />
         <attr name="logo" />
         <attr name="process" />
         <attr name="authorities" />
@@ -1375,6 +1415,8 @@
         <attr name="label" />
         <attr name="description" />
         <attr name="icon" />
+        <!-- @hide -->
+        <attr name="banner" />
         <attr name="logo" />
         <attr name="permission" />
         <attr name="process" />
@@ -1417,6 +1459,8 @@
         <attr name="label" />
         <attr name="description" />
         <attr name="icon" />
+        <!-- @hide -->
+        <attr name="banner" />
         <attr name="logo" />
         <attr name="permission" />
         <attr name="process" />
@@ -1451,6 +1495,8 @@
         <attr name="label" />
         <attr name="description" />
         <attr name="icon" />
+        <!-- @hide -->
+        <attr name="banner" />
         <attr name="logo" />
         <attr name="launchMode" />
         <attr name="screenOrientation" />
@@ -1486,6 +1532,7 @@
         <!-- @hide This broacast receiver will only receive broadcasts for the
              primary user.  Can only be used with receivers. -->
         <attr name="primaryUserOnly" format="boolean" />
+        <attr name="allowEmbedded" />
     </declare-styleable>
     
     <!-- The <code>activity-alias</code> tag declares a new
@@ -1514,6 +1561,8 @@
         <attr name="label" />
         <attr name="description" />
         <attr name="icon" />
+        <!-- @hide -->
+        <attr name="banner" />
         <attr name="logo" />
         <attr name="permission" />
         <!-- Specify whether the activity-alias is enabled or not (that is, can be instantiated by the system).
@@ -1585,6 +1634,8 @@
          parent="AndroidManifestActivity AndroidManifestReceiver AndroidManifestService">
         <attr name="label" />
         <attr name="icon" />
+        <!-- @hide -->
+        <attr name="banner" />
         <attr name="logo" />
         <attr name="priority" />
     </declare-styleable>
@@ -1713,6 +1764,8 @@
         <attr name="targetPackage" />
         <attr name="label" />
         <attr name="icon" />
+        <!-- @hide -->
+        <attr name="banner" />
         <attr name="logo" />
         <attr name="handleProfiling" />
         <attr name="functionalTest" />
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index 28e7af7..0c3e754 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -150,6 +150,8 @@
     <color name="link_text_holo_dark">#5c5cff</color>
     <color name="link_text_holo_light">#0000ee</color>
 
+    <color name="micro_text_light">#434343</color>
+
     <!-- Group buttons -->
     <eat-comment />
     <color name="group_button_dialog_pressed_holo_dark">#46c5c1ff</color>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index a3b8132..9d27164 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -352,10 +352,6 @@
     <!-- Wifi driver supports batched scan -->
     <bool translatable="false" name="config_wifi_batched_scan_supported">false</bool>
 
-    <!-- Wifi driver's fallback country code; WS is ISO-Alpha2 code for Samoa which
-         has restrictions on can be scanned; which may satisfy quite a few regulatory issues. -->
-    <string translatable="false" name="config_wifi_unknown_country_code">WS</string>
-
     <!-- Flag indicating whether the we should enable the automatic brightness in Settings.
          Software implementation will be used if config_hardware_auto_brightness_available is not set -->
     <bool name="config_automatic_brightness_available">false</bool>
@@ -374,6 +370,17 @@
     <!-- If this is true, key chords can be used to take a screenshot on the device. -->
     <bool name="config_enableScreenshotChord">true</bool>
 
+    <!-- Auto-rotation behavior -->
+
+    <!-- If true, enables auto-rotation features using the accelerometer.
+         Otherwise, auto-rotation is disabled.  Applications may still request
+         to use specific orientations but the sensor is ignored and sensor-based
+         orientations are not available.  Furthermore, all auto-rotation related
+         settings are omitted from the system UI.  In certain situations we may
+         still use the accelerometer to determine the orientation, such as when
+         docked if the dock is configured to enable the accelerometer. -->
+    <bool name="config_supportAutoRotation">true</bool>
+
     <!-- If true, the screen can be rotated via the accelerometer in all 4
          rotations as the default behavior. -->
     <bool name="config_allowAllRotations">false</bool>
@@ -386,57 +393,12 @@
          true here reverses that logic. -->
     <bool name="config_reverseDefaultRotation">false</bool>
 
+    <!-- Lid switch behavior -->
+
     <!-- The number of degrees to rotate the display when the keyboard is open.
          A value of -1 means no change in orientation by default. -->
     <integer name="config_lidOpenRotation">-1</integer>
 
-    <!-- The number of degrees to rotate the display when the device is in a desk dock.
-         A value of -1 means no change in orientation by default. -->
-    <integer name="config_deskDockRotation">-1</integer>
-
-    <!-- The number of degrees to rotate the display when the device is in a car dock.
-         A value of -1 means no change in orientation by default. -->
-    <integer name="config_carDockRotation">-1</integer>
-
-    <!-- The number of degrees to rotate the display when the device has HDMI connected
-         but is not in a dock.  A value of -1 means no change in orientation by default.
-         Use -1 except on older devices whose Hardware Composer HAL does not
-         provide full support for multiple displays.  -->
-    <integer name="config_undockedHdmiRotation">-1</integer>
-
-    <!-- Control the default UI mode type to use when there is no other type override
-         happening.  One of the following values (See Configuration.java):
-             1  UI_MODE_TYPE_NORMAL
-             4  UI_MODE_TYPE_TELEVISION
-             5  UI_MODE_TYPE_APPLIANCE
-         Any other values will have surprising consequences. -->
-    <integer name="config_defaultUiModeType">1</integer>
-
-    <!-- Control whether being in the desk dock (and powered) always
-         keeps the screen on.  By default it stays on when plugged in to
-         AC.  0 will not keep it on; or together 1 to stay on when plugged
-         in to AC and 2 to stay on when plugged in to USB.  (So 3 for both.) -->
-    <integer name="config_deskDockKeepsScreenOn">1</integer>
-
-    <!-- Control whether being in the car dock (and powered) always
-         keeps the screen on.  By default it stays on when plugged in to
-         AC.  0 will not keep it on; or together 1 to stay on when plugged
-         in to AC and 2 to stay on when plugged in to USB.  (So 3 for both.) -->
-    <integer name="config_carDockKeepsScreenOn">1</integer>
-
-    <!-- Control whether being in the desk dock should enable accelerometer
-         based screen orientation.  This defaults to true because it is
-         common for desk docks to be sold in a variety of form factors
-         with different orientations.  Since we cannot always tell these docks
-         apart and the docks cannot report their true orientation on their own,
-         we rely on gravity to determine the effective orientation. -->
-    <bool name="config_deskDockEnablesAccelerometer">true</bool>
-
-    <!-- Control whether being in the car dock should enable accelerometer based
-         screen orientation.  This defaults to true because putting a device in
-         a car dock make the accelerometer more a physical input (like a lid). -->
-    <bool name="config_carDockEnablesAccelerometer">true</bool>
-
     <!-- Indicate whether the lid state impacts the accessibility of
          the physical keyboard.  0 means it doesn't, 1 means it is accessible
          when the lid is open, 2 means it is accessible when the lid is
@@ -454,6 +416,61 @@
          The default is false. -->
     <bool name="config_lidControlsSleep">false</bool>
 
+    <!-- Desk dock behavior -->
+
+    <!-- The number of degrees to rotate the display when the device is in a desk dock.
+         A value of -1 means no change in orientation by default. -->
+    <integer name="config_deskDockRotation">-1</integer>
+
+    <!-- Control whether being in the desk dock (and powered) always
+         keeps the screen on.  By default it stays on when plugged in to
+         AC.  0 will not keep it on; or together 1 to stay on when plugged
+         in to AC and 2 to stay on when plugged in to USB.  (So 3 for both.) -->
+    <integer name="config_deskDockKeepsScreenOn">1</integer>
+
+    <!-- Control whether being in the desk dock should enable accelerometer
+         based screen orientation.  This defaults to true because it is
+         common for desk docks to be sold in a variety of form factors
+         with different orientations.  Since we cannot always tell these docks
+         apart and the docks cannot report their true orientation on their own,
+         we rely on gravity to determine the effective orientation. -->
+    <bool name="config_deskDockEnablesAccelerometer">true</bool>
+
+    <!-- Car dock behavior -->
+
+    <!-- The number of degrees to rotate the display when the device is in a car dock.
+         A value of -1 means no change in orientation by default. -->
+    <integer name="config_carDockRotation">-1</integer>
+
+    <!-- Control whether being in the car dock (and powered) always
+         keeps the screen on.  By default it stays on when plugged in to
+         AC.  0 will not keep it on; or together 1 to stay on when plugged
+         in to AC and 2 to stay on when plugged in to USB.  (So 3 for both.) -->
+    <integer name="config_carDockKeepsScreenOn">1</integer>
+
+    <!-- Control whether being in the car dock should enable accelerometer based
+         screen orientation.  This defaults to true because putting a device in
+         a car dock make the accelerometer more a physical input (like a lid). -->
+
+    <bool name="config_carDockEnablesAccelerometer">true</bool>
+
+    <!-- HDMI behavior -->
+
+    <!-- The number of degrees to rotate the display when the device has HDMI connected
+         but is not in a dock.  A value of -1 means no change in orientation by default.
+         Use -1 except on older devices whose Hardware Composer HAL does not
+         provide full support for multiple displays.  -->
+    <integer name="config_undockedHdmiRotation">-1</integer>
+
+    <!-- Control the default UI mode type to use when there is no other type override
+         happening.  One of the following values (See Configuration.java):
+             1  UI_MODE_TYPE_NORMAL
+             4  UI_MODE_TYPE_TELEVISION
+             5  UI_MODE_TYPE_APPLIANCE
+             6  UI_MODE_TYPE_WATCH
+         Any other values will have surprising consequences. -->
+    <integer name="config_defaultUiModeType">1</integer>
+
     <!-- Indicate whether to allow the device to suspend when the screen is off
          due to the proximity sensor.  This resource should only be set to true
          if the sensor HAL correctly handles the proximity sensor as a wake-up source.
@@ -656,6 +673,11 @@
          Must be in the range specified by minimum and maximum. -->
     <integer name="config_screenBrightnessSettingDefault">102</integer>
 
+    <!-- Screen brightness used to dim the screen while dozing in a very low power state.
+         May be less than the minimum allowed brightness setting
+         that can be set by the user. -->
+    <integer name="config_screenBrightnessDoze">1</integer>
+
     <!-- Screen brightness used to dim the screen when the user activity
          timeout expires.  May be less than the minimum allowed brightness setting
          that can be set by the user. -->
@@ -923,7 +945,7 @@
     <!-- Max space (in MB) allocated to DownloadManager to store the downloaded
          files if they are to be stored in DownloadManager's data dir,
          which typically is /data/data/com.android.providers.downloads/files -->
-    <integer name="config_downloadDataDirSize">100</integer>
+    <integer name="config_downloadDataDirSize">200</integer>
 
     <!-- Max number of downloads allowed to proceed concurrently -->
     <integer name="config_MaxConcurrentDownloadsAllowed">5</integer>
@@ -1076,8 +1098,16 @@
     <!-- Name of the wimax state tracker clas -->
     <string name="config_wimaxStateTrackerClassname" translatable="false"></string>
 
-    <!-- Is the dreams feature supported? -->
+    <!-- Specifies whether the dreams feature should be supported.
+         When true, the system will allow the user to configure dreams (screensavers)
+         to launch when a user activity timeout occurs or the system is told to nap.
+         When false, the dreams feature will be disabled (this does not affect dozing).
+
+         Consider setting this resource to false or disabling dreams by default when a
+         doze component is specified below since dreaming will supercede dozing and
+         will prevent the system from entering a low power state until the dream ends. -->
     <bool name="config_dreamsSupported">true</bool>
+
     <!-- If supported, are dreams enabled? (by default) -->
     <bool name="config_dreamsEnabledByDefault">true</bool>
     <!-- If supported and enabled, are dreams activated when docked? (by default) -->
@@ -1087,10 +1117,83 @@
     <!-- ComponentName of the default dream (Settings.Secure.SCREENSAVER_COMPONENT) -->
     <string name="config_dreamsDefaultComponent">com.google.android.deskclock/com.android.deskclock.Screensaver</string>
 
+    <!-- Are we allowed to dream while not plugged in? -->
+    <bool name="config_dreamsEnabledOnBattery">false</bool>
+    <!-- Minimum battery level to allow dreaming when powered.
+         Use -1 to disable this safety feature. -->
+    <integer name="config_dreamsBatteryLevelMinimumWhenPowered">-1</integer>
+    <!-- Minimum battery level to allow dreaming when not powered.
+         Use -1 to disable this safety feature. -->
+    <integer name="config_dreamsBatteryLevelMinimumWhenNotPowered">15</integer>
+    <!-- If the battery level drops by this percentage and the user activity timeout
+         has expired, then assume the device is receiving insufficient current to charge
+         effectively and terminate the dream.  Use -1 to disable this safety feature.  -->
+    <integer name="config_dreamsBatteryLevelDrainCutoff">5</integer>
+
+    <!-- ComponentName of a dream to show whenever the system would otherwise have
+         gone to sleep.  When the PowerManager is asked to go to sleep, it will instead
+         try to start this dream if possible.  The dream should typically call startDozing()
+         to put the display into a low power state and allow the application processor
+         to be suspended.  When the dream ends, the system will go to sleep as usual.
+         Specify the component name (Settings.Secure.SCREENSAVER_COMPONENT) or an
+         empty string if none.
+
+         Note that doze dreams are not subject to the same start conditions as ordinary dreams.
+         Doze dreams will run whenever the power manager is in a dozing state. -->
+    <string name="config_dozeComponent"></string>
+
+    <!-- Power Management: Specifies whether to decouple the auto-suspend state of the
+         device from the display on/off state.
+
+         When false, autosuspend_disable() will be called before the display is turned on
+         and autosuspend_enable() will be called after the display is turned off.
+         This mode provides best compatibility for devices using legacy power management
+         features such as early suspend / late resume.
+
+         When true, autosuspend_display() and autosuspend_enable() will be called
+         independently of whether the display is being turned on or off.  This mode
+         enables the power manager to suspend the application processor while the
+         display is on.
+
+         This resource should be set to "true" when a doze component has been specified
+         to maximize power savings but not all devices support it.
+
+         Refer to autosuspend.h for details.
+    -->
+    <bool name="config_powerDecoupleAutoSuspendModeFromDisplay">false</bool>
+
+    <!-- Power Management: Specifies whether to decouple the interactive state of the
+         device from the display on/off state.
+
+         When false, setInteractive(..., true) will be called before the display is turned on
+         and setInteractive(..., false) will be called after the display is turned off.
+         This mode provides best compatibility for devices that expect the interactive
+         state to be tied to the display state.
+
+         When true, setInteractive(...) will be called independently of whether the display
+         is being turned on or off.  This mode enables the power manager to reduce
+         clocks and disable the touch controller while the display is on.
+
+         This resource should be set to "true" when a doze component has been specified
+         to maximize power savings but not all devices support it.
+
+         Refer to power.h for details.
+    -->
+    <bool name="config_powerDecoupleInteractiveModeFromDisplay">false</bool>
+
     <!-- Base "touch slop" value used by ViewConfiguration as a
          movement threshold where scrolling should begin. -->
     <dimen name="config_viewConfigurationTouchSlop">8dp</dimen>
 
+    <!-- Minimum velocity to initiate a fling, as measured in dips per second. -->
+    <dimen name="config_viewMinFlingVelocity">50dp</dimen>
+
+    <!-- Maximum velocity to initiate a fling, as measured in dips per second. -->
+    <dimen name="config_viewMaxFlingVelocity">8000dp</dimen>
+
+    <!-- Amount of time in ms the user needs to press the relevant key to bring up the global actions dialog -->
+    <integer name="config_globalActionsKeyTimeout">500</integer>
+
     <!-- Maximum number of grid columns permitted in the ResolverActivity
          used for picking activities to handle an intent. -->
     <integer name="config_maxResolverActivityColumns">2</integer>
@@ -1234,6 +1337,12 @@
          Example: com.google.android.myapp/.resolver.MyResolverActivity  -->
     <string name="config_customResolverActivity"></string>
 
+    <!-- Name of the activity or service that prompts the user to reject, accept, or whitelist
+         an adb host's public key, when an unwhitelisted host connects to the local adbd.
+         Can be customized for other product types -->
+    <string name="config_customAdbPublicKeyConfirmationComponent"
+            >com.android.systemui/com.android.systemui.usb.UsbDebuggingActivity</string>
+
     <!-- Apps that are authorized to access shared accounts, overridden by product overlays -->
     <string name="config_appsAuthorizedForSharedAccounts">;com.android.settings;</string>
 
@@ -1316,4 +1425,26 @@
          1 - The device DOES have a permanent menu key; ignore autodetection.
          2 - The device DOES NOT have a permanent menu key; ignore autodetection. -->
     <integer name="config_overrideHasPermanentMenuKey">0</integer>
+
+    <!-- default window inset isRound property -->
+    <bool name="config_windowIsRound">false</bool>
+
+    <!-- Defines the default set of global actions. Actions may still be disabled or hidden based
+         on the current state of the device.
+         Each item must be one of the following strings:
+         "power" = Power off
+         "settings" = An action to launch settings
+         "airplane" = Airplane mode toggle
+         "bugreport" = Take bug report, if available
+         "silent" = silent mode
+         "users" = list of users
+         -->
+    <string-array translatable="false" name="config_globalActionsList">
+        <item>power</item>
+        <item>airplane</item>
+        <item>bugreport</item>
+        <item>silent</item>
+        <item>users</item>
+    </string-array>
+
 </resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index f96195c..c97daf7 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -161,6 +161,8 @@
     <!-- Preferred width of the search view. -->
     <dimen name="search_view_preferred_width">320dip</dimen>
 
+    <!-- Dialog padding for round display -->
+    <dimen name="alert_dialog_round_padding">27dip</dimen>
     <!-- Dialog title height -->
     <dimen name="alert_dialog_title_height">64dip</dimen>
     <!-- Dialog button bar height -->
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 8187939..a2493a7 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2087,4 +2087,11 @@
   <public type="style" name="Theme.DeviceDefault.NoActionBar.TranslucentDecor" id="0x010301e3" />
   <public type="style" name="Theme.DeviceDefault.Light.NoActionBar.TranslucentDecor" id="0x010301e4" />
 
+<!-- ===============================================================
+    Resources added in version 20 of the platform
+    =============================================================== -->
+  <eat-comment />
+
+  <public type="attr" name="windowSwipeToDismiss" id="0x10103f3" />
+  <public type="attr" name="allowEmbedded" id="0x10103f5" />
 </resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 538003f..a923104 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -278,6 +278,8 @@
     <!-- If MMS discovers there isn't much space left on the device, it will show a toast with this message. -->
     <string name="low_memory" product="tablet">Tablet storage is full. Delete some files to free space.</string>
     <!-- If MMS discovers there isn't much space left on the device, it will show a toast with this message. -->
+    <string name="low_memory" product="watch">Watch storage is full. Delete some files to free space.</string>
+    <!-- If MMS discovers there isn't much space left on the device, it will show a toast with this message. -->
     <string name="low_memory" product="default">Phone storage is full. Delete some files to free space.</string>
 
     <!-- SSL CA cert notification --> <skip />
@@ -324,6 +326,9 @@
     <!-- Shutdown Confirmation Dialog.  When the user chooses to power off the phone, there will
          be a confirmation dialog.  This is the message. -->
     <string name="shutdown_confirm" product="tablet">Your tablet will shut down.</string>
+    <!-- Shutdown Confirmation Dialog.  When the user chooses to power off the watch, there will
+         be a confirmation dialog.  This is the message. -->
+    <string name="shutdown_confirm" product="watch">Your watch will shut down.</string>
     <!-- Shutdown Confirmation Dialog.  When the user chooses to power off the phone, there will
          be a confirmation dialog.  This is the message. -->
     <string name="shutdown_confirm" product="default">Your phone will shut down.</string>
@@ -394,6 +399,9 @@
     <!-- status message in phone options dialog for when airplane mode is off -->
     <string name="global_actions_airplane_mode_off_status">Airplane mode is OFF</string>
 
+    <!-- label for item that launches settings in phone options dialog [CHAR LIMIT=15]-->
+    <string name="global_action_settings">Settings</string>
+
     <!-- Text to use when the number in a notification info is too large
          (greater than status_bar_notification_info_maxnum, defined in
          values/config.xml) and must be truncated. May need to be localized
@@ -625,9 +633,9 @@
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_processOutgoingCalls">reroute outgoing calls</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_processOutgoingCalls">Allows the app to see the
-        number being dialed during an outgoing call with the option to redirect
-        the call to a different number or abort the call altogether.</string>
+    <string name="permdesc_processOutgoingCalls">Allows the app to process
+      outgoing calls and change the number to be dialed. This permission allows
+      the app to monitor, redirect, or prevent outgoing calls.</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_receiveSms">receive text messages (SMS)</string>
@@ -1328,6 +1336,14 @@
       as your name and contact information.  This means the app can identify you
       and may send your profile information to others.</string>
 
+    <!-- Title of the body sensors permission, listed so the user can decide whether to allow the application to access body sensor data. [CHAR LIMIT=30] -->
+    <string name="permlab_bodySensors">body sensors (like heart rate monitors)
+    </string>
+    <!-- Description of the body sensors permission, listed so the user can decide whether to allow the application to access data from body sensors. [CHAR LIMIT=NONE] -->
+    <string name="permdesc_bodySensors" product="default">Allows the app to
+      access data from sensors you use to measure what’s happening inside your
+      body, such as heart rate.</string>
+
     <!-- Title of the read social stream permission, listed so the user can decide whether to allow the application to read information from the user's social stream. [CHAR LIMIT=30] -->
     <string name="permlab_readSocialStream" product="default">read your social stream</string>
     <string name="permdesc_readSocialStream" product="default">Allows the app
@@ -1993,6 +2009,11 @@
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_accessNetworkConditions">Allows an application to listen for observations on network conditions. 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_accessDrmCertificates">access DRM certificates</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_accessDrmCertificates">Allows an application to provision and use DRM certficates. Should never be needed for normal apps.</string>
+
     <!-- Policy administration -->
 
     <!-- Title of policy access to limiting the user's password choices -->
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index cb2fd6d..4d4feeee 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -225,6 +225,14 @@
         <item name="windowExitAnimation">@anim/fast_fade_out</item>
     </style>
 
+    <!-- Window animations for swipe-dismissable windows. {@hide} -->
+    <style name="Animation.SwipeDismiss">
+        <item name="taskOpenEnterAnimation">@anim/swipe_window_enter</item>
+        <item name="taskOpenExitAnimation">@anim/swipe_window_exit</item>
+        <item name="taskCloseEnterAnimation">@anim/swipe_window_enter</item>
+        <item name="taskCloseExitAnimation">@anim/swipe_window_exit</item>
+    </style>
+
     <!-- Status Bar Styles -->
     <style name="TextAppearance.StatusBar">
         <item name="android:textAppearance">?android:attr/textAppearanceSmall</item>
diff --git a/core/res/res/values/styles_micro.xml b/core/res/res/values/styles_micro.xml
new file mode 100644
index 0000000..5bac1f9
--- /dev/null
+++ b/core/res/res/values/styles_micro.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<resources>
+    <style name="AlertDialog.Micro" parent="AlertDialog.Holo.Light">
+        <item name="fullDark">@null</item>
+        <item name="topDark">@null</item>
+        <item name="centerDark">@null</item>
+        <item name="bottomDark">@null</item>
+        <item name="fullBright">@null</item>
+        <item name="topBright">@null</item>
+        <item name="centerBright">@null</item>
+        <item name="bottomBright">@null</item>
+        <item name="bottomMedium">@null</item>
+        <item name="centerMedium">@null</item>
+        <item name="layout">@layout/alert_dialog_micro</item>
+    </style>
+
+    <style name="DialogWindowTitle.Micro">
+        <item name="maxLines">1</item>
+        <item name="scrollHorizontally">true</item>
+        <item name="textAppearance">@style/TextAppearance.Micro.DialogWindowTitle</item>
+    </style>
+
+    <style name="TextAppearance.Micro" parent="TextAppearance.Holo">
+        <item name="textSize">20sp</item>
+        <item name="fontFamily">sans-serif-condensed-light</item>
+        <item name="textColor">@color/micro_text_light</item>
+    </style>
+
+    <style name="TextAppearance.Micro.DialogWindowTitle" parent="TextAppearance.Holo.DialogWindowTitle">
+        <item name="textSize">20sp</item>
+        <item name="fontFamily">sans-serif-condensed-light</item>
+        <item name="textColor">@color/micro_text_light</item>
+    </style>
+
+    <style name="Widget.Micro" parent="Widget.Holo" />
+
+    <style name="Widget.Micro.TextView">
+        <item name="fontFamily">sans-serif-condensed</item>
+    </style>
+
+    <style name="Widget.Micro.NumberPicker">
+        <item name="internalLayout">@layout/number_picker_with_selector_wheel_micro</item>
+        <item name="solidColor">@color/transparent</item>
+        <item name="selectionDivider">@drawable/numberpicker_selection_divider</item>
+        <item name="selectionDividerHeight">0dip</item>
+        <item name="selectionDividersDistance">104dip</item>
+        <item name="internalMinWidth">64dip</item>
+        <item name="internalMaxHeight">180dip</item>
+        <item name="virtualButtonPressedDrawable">?attr/selectableItemBackground</item>
+        <item name="descendantFocusability">blocksDescendants</item>
+    </style>
+
+</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 1200276..72ff32f 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -120,6 +120,7 @@
   <java-symbol type="id" name="overlay_display_window_title" />
   <java-symbol type="id" name="package_label" />
   <java-symbol type="id" name="packages_list" />
+  <java-symbol type="id" name="parentPanel" />
   <java-symbol type="id" name="pause" />
   <java-symbol type="id" name="perms_list" />
   <java-symbol type="id" name="perm_icon" />
@@ -288,6 +289,7 @@
   <java-symbol type="bool" name="config_useFixedVolume" />
   <java-symbol type="bool" name="config_forceDefaultOrientation" />
   <java-symbol type="bool" name="config_wifi_batched_scan_supported" />
+  <java-symbol type="bool" name="config_windowIsRound" />
 
   <java-symbol type="integer" name="config_cursorWindowSize" />
   <java-symbol type="integer" name="config_extraFreeKbytesAdjust" />
@@ -323,8 +325,11 @@
   <java-symbol type="color" name="tab_indicator_text_v4" />
 
   <java-symbol type="dimen" name="accessibility_touch_slop" />
+  <java-symbol type="dimen" name="alert_dialog_round_padding"/>
   <java-symbol type="dimen" name="config_prefDialogWidth" />
   <java-symbol type="dimen" name="config_viewConfigurationTouchSlop" />
+  <java-symbol type="dimen" name="config_viewMinFlingVelocity" />
+  <java-symbol type="dimen" name="config_viewMaxFlingVelocity" />
   <java-symbol type="dimen" name="default_app_widget_padding_bottom" />
   <java-symbol type="dimen" name="default_app_widget_padding_left" />
   <java-symbol type="dimen" name="default_app_widget_padding_right" />
@@ -478,7 +483,6 @@
   <java-symbol type="string" name="config_ntpServer" />
   <java-symbol type="string" name="config_tether_apndata" />
   <java-symbol type="string" name="config_useragentprofile_url" />
-  <java-symbol type="string" name="config_wifi_unknown_country_code" />
   <java-symbol type="string" name="config_wifi_p2p_device_type" />
   <java-symbol type="string" name="contentServiceSync" />
   <java-symbol type="string" name="contentServiceSyncNotificationTitle" />
@@ -988,6 +992,7 @@
   <java-symbol type="array" name="config_operatorConsideredNonRoaming" />
   <java-symbol type="array" name="config_sameNamedOperatorConsideredRoaming" />
   <java-symbol type="array" name="config_callBarringMMI" />
+  <java-symbol type="array" name="config_globalActionsList" />
 
   <java-symbol type="drawable" name="default_wallpaper" />
   <java-symbol type="drawable" name="indicator_input_error" />
@@ -1308,6 +1313,7 @@
   <java-symbol type="bool" name="config_lidControlsSleep" />
   <java-symbol type="bool" name="config_reverseDefaultRotation" />
   <java-symbol type="bool" name="config_showNavigationBar" />
+  <java-symbol type="bool" name="config_supportAutoRotation" />
   <java-symbol type="bool" name="target_honeycomb_needs_options_menu" />
   <java-symbol type="dimen" name="navigation_bar_height" />
   <java-symbol type="dimen" name="navigation_bar_height_landscape" />
@@ -1375,6 +1381,7 @@
   <java-symbol type="layout" name="screen_progress" />
   <java-symbol type="layout" name="screen_simple" />
   <java-symbol type="layout" name="screen_simple_overlay_action_mode" />
+  <java-symbol type="layout" name="screen_swipe_dismiss" />
   <java-symbol type="layout" name="screen_title" />
   <java-symbol type="layout" name="screen_title_icons" />
   <java-symbol type="string" name="system_ui_date_pattern" />
@@ -1387,6 +1394,7 @@
   <java-symbol type="string" name="global_actions_airplane_mode_on_status" />
   <java-symbol type="string" name="global_actions_toggle_airplane_mode" />
   <java-symbol type="string" name="global_action_bug_report" />
+  <java-symbol type="string" name="global_action_settings" />
   <java-symbol type="string" name="global_action_silent_mode_off_status" />
   <java-symbol type="string" name="global_action_silent_mode_on_status" />
   <java-symbol type="string" name="global_action_toggle_silent_mode" />
@@ -1459,6 +1467,7 @@
   <java-symbol type="color" name="input_method_navigation_guard" />
   <java-symbol type="drawable" name="ic_notification_ime_default" />
   <java-symbol type="drawable" name="ic_menu_refresh" />
+  <java-symbol type="drawable" name="ic_settings" />
   <java-symbol type="drawable" name="stat_notify_car_mode" />
   <java-symbol type="drawable" name="stat_notify_disabled" />
   <java-symbol type="drawable" name="stat_notify_disk_full" />
@@ -1506,6 +1515,7 @@
   <java-symbol type="integer" name="config_screenBrightnessSettingMaximum" />
   <java-symbol type="integer" name="config_screenBrightnessSettingDefault" />
   <java-symbol type="integer" name="config_screenBrightnessDim" />
+  <java-symbol type="integer" name="config_screenBrightnessDoze" />
   <java-symbol type="integer" name="config_shutdownBatteryTemperature" />
   <java-symbol type="integer" name="config_undockedHdmiRotation" />
   <java-symbol type="integer" name="config_virtualKeyQuietTimeMillis" />
@@ -1606,20 +1616,30 @@
   <java-symbol type="string" name="wifi_display_notification_connected_message" />
   <java-symbol type="string" name="wifi_display_notification_disconnect" />
   <java-symbol type="style" name="Theme.Dialog.AppError" />
+  <java-symbol type="style" name="Theme.Micro.Dialog.Alert" />
   <java-symbol type="style" name="Theme.Toast" />
   <java-symbol type="xml" name="storage_list" />
   <java-symbol type="bool" name="config_dreamsSupported" />
   <java-symbol type="bool" name="config_dreamsEnabledByDefault" />
+  <java-symbol type="bool" name="config_dreamsEnabledOnBattery" />
   <java-symbol type="bool" name="config_dreamsActivatedOnDockByDefault" />
   <java-symbol type="bool" name="config_dreamsActivatedOnSleepByDefault" />
+  <java-symbol type="integer" name="config_dreamsBatteryLevelMinimumWhenPowered" />
+  <java-symbol type="integer" name="config_dreamsBatteryLevelMinimumWhenNotPowered" />
+  <java-symbol type="integer" name="config_dreamsBatteryLevelDrainCutoff" />
   <java-symbol type="string" name="config_dreamsDefaultComponent" />
+  <java-symbol type="string" name="config_dozeComponent" />
   <java-symbol type="string" name="enable_explore_by_touch_warning_title" />
   <java-symbol type="string" name="enable_explore_by_touch_warning_message" />
+  <java-symbol type="bool" name="config_powerDecoupleAutoSuspendModeFromDisplay" />
+  <java-symbol type="bool" name="config_powerDecoupleInteractiveModeFromDisplay" />
+  <java-symbol type="string" name="config_customAdbPublicKeyConfirmationComponent" />
 
   <java-symbol type="layout" name="resolver_list" />
   <java-symbol type="id" name="resolver_list" />
   <java-symbol type="id" name="button_once" />
   <java-symbol type="id" name="button_always" />
+  <java-symbol type="integer" name="config_globalActionsKeyTimeout" />
   <java-symbol type="integer" name="config_maxResolverActivityColumns" />
   <java-symbol type="array" name="config_notificationScorers" />
 
diff --git a/core/res/res/values/themes_micro.xml b/core/res/res/values/themes_micro.xml
new file mode 100644
index 0000000..9647947
--- /dev/null
+++ b/core/res/res/values/themes_micro.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<resources>
+    <style name="Theme.Micro" parent="Theme.Holo.NoActionBar">
+        <item name="alertDialogTheme">@style/Theme.Micro.Dialog.Alert</item>
+        <item name="alertDialogStyle">@style/AlertDialog.Micro</item>
+        <item name="dialogTheme">@style/Theme.Micro.Dialog</item>
+        <item name="textViewStyle">@style/Widget.Micro.TextView</item>
+
+        <item name="numberPickerStyle">@style/Widget.Micro.NumberPicker</item>
+        <item name="windowAnimationStyle">@style/Animation.SwipeDismiss</item>
+        <item name="windowIsFloating">false</item>
+        <item name="windowIsTranslucent">true</item>
+        <item name="windowSwipeToDismiss">true</item>
+	</style>
+
+    <style name="Theme.Micro.Light" parent="Theme.Holo.Light.NoActionBar">
+        <item name="alertDialogTheme">@style/Theme.Micro.Dialog.Alert</item>
+        <item name="alertDialogStyle">@style/AlertDialog.Micro</item>
+        <item name="dialogTheme">@style/Theme.Micro.Dialog</item>
+        <item name="textViewStyle">@style/Widget.Micro.TextView</item>
+        <item name="numberPickerStyle">@style/Widget.Micro.NumberPicker</item>
+        <item name="windowAnimationStyle">@style/Animation.SwipeDismiss</item>
+        <item name="windowIsFloating">false</item>
+        <item name="windowIsTranslucent">true</item>
+        <item name="windowSwipeToDismiss">true</item>
+    </style>
+
+    <style name="Theme.Micro.Dialog" parent="Theme.Holo.Light.Dialog">
+        <item name="windowTitleStyle">@android:style/DialogWindowTitle.Micro</item>
+        <item name="windowIsFloating">false</item>
+        <item name="windowFullscreen">true</item>
+        <item name="textAppearance">@style/TextAppearance.Micro</item>
+        <item name="textAppearanceInverse">@style/TextAppearance.Micro</item>
+    </style>
+
+    <style name="Theme.Micro.Dialog.Alert">
+        <item name="windowTitleStyle">@style/DialogWindowTitle.Micro</item>
+        <item name="alertDialogStyle">@style/AlertDialog.Micro</item>
+        <item name="windowIsFloating">false</item>
+        <item name="windowBackground">@android:color/transparent</item>
+        <item name="windowOverscan">true</item>
+        <item name="windowContentOverlay">@null</item>
+        <item name="android:windowMinWidthMajor">@android:dimen/dialog_min_width_major</item>
+        <item name="android:windowMinWidthMinor">@android:dimen/dialog_min_width_minor</item>
+    </style>
+
+    <style name="Theme.Micro.Dialog.AppError" parent="Theme.Micro.Dialog">
+        <item name="windowBackground">@null</item>
+        <item name="alertDialogStyle">@style/AlertDialog.Micro</item>
+        <item name="windowOverscan">true</item>
+        <item name="windowCloseOnTouchOutside">false</item>
+        <item name="textSize">20sp</item>
+        <item name="fontFamily">sans-serif-condensed-light</item>
+        <item name="textColor">@color/micro_text_light</item>
+    </style>
+</resources>
diff --git a/core/tests/bluetoothtests/AndroidManifest.xml b/core/tests/bluetoothtests/AndroidManifest.xml
index 60b6dc1..cbfa84d 100644
--- a/core/tests/bluetoothtests/AndroidManifest.xml
+++ b/core/tests/bluetoothtests/AndroidManifest.xml
@@ -31,5 +31,8 @@
     <instrumentation android:name="android.bluetooth.BluetoothTestRunner"
             android:targetPackage="com.android.bluetooth.tests"
             android:label="Bluetooth Tests" />
+    <instrumentation android:name="android.bluetooth.BluetoothInstrumentation"
+            android:targetPackage="com.android.bluetooth.tests"
+            android:label="Bluetooth Test Utils" />
 
 </manifest>
diff --git a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothInstrumentation.java b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothInstrumentation.java
new file mode 100644
index 0000000..67203b2
--- /dev/null
+++ b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothInstrumentation.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.bluetooth;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.content.Context;
+import android.os.Bundle;
+
+public class BluetoothInstrumentation extends Instrumentation {
+
+    private BluetoothTestUtils mUtils = null;
+    private BluetoothAdapter mAdapter = null;
+    private Bundle mArgs = null;
+    private Bundle mSuccessResult = null;
+
+    private BluetoothTestUtils getBluetoothTestUtils() {
+        if (mUtils == null) {
+            mUtils = new BluetoothTestUtils(getContext(),
+                    BluetoothInstrumentation.class.getSimpleName());
+        }
+        return mUtils;
+    }
+
+    private BluetoothAdapter getBluetoothAdapter() {
+        if (mAdapter == null) {
+            mAdapter = ((BluetoothManager)getContext().getSystemService(
+                    Context.BLUETOOTH_SERVICE)).getAdapter();
+        }
+        return mAdapter;
+    }
+
+    @Override
+    public void onCreate(Bundle arguments) {
+        super.onCreate(arguments);
+        mArgs = arguments;
+        // create the default result response, but only use it in success code path
+        mSuccessResult = new Bundle();
+        mSuccessResult.putString("result", "SUCCESS");
+        start();
+    }
+
+    @Override
+    public void onStart() {
+        String command = mArgs.getString("command");
+        if ("enable".equals(command)) {
+            enable();
+        } else if ("disable".equals(command)) {
+            disable();
+        } else if ("unpairAll".equals(command)) {
+            unpairAll();
+        } else if ("getName".equals(command)) {
+            getName();
+        } else if ("getAddress".equals(command)) {
+            getAddress();
+        } else {
+            finish(null);
+        }
+    }
+
+    public void enable() {
+        getBluetoothTestUtils().enable(getBluetoothAdapter());
+        finish(mSuccessResult);
+    }
+
+    public void disable() {
+        getBluetoothTestUtils().disable(getBluetoothAdapter());
+        finish(mSuccessResult);
+    }
+
+    public void unpairAll() {
+        getBluetoothTestUtils().unpairAll(getBluetoothAdapter());
+        finish(mSuccessResult);
+    }
+
+    public void getName() {
+        String name = getBluetoothAdapter().getName();
+        mSuccessResult.putString("name", name);
+        finish(mSuccessResult);
+    }
+
+    public void getAddress() {
+        String name = getBluetoothAdapter().getAddress();
+        mSuccessResult.putString("address", name);
+        finish(mSuccessResult);
+    }
+
+    public void finish(Bundle result) {
+        if (result == null) {
+            result = new Bundle();
+        }
+        finish(Activity.RESULT_OK, result);
+    }
+}
diff --git a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestUtils.java b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestUtils.java
index 4858be8..8fbd214 100644
--- a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestUtils.java
+++ b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestUtils.java
@@ -34,6 +34,7 @@
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Set;
 
 public class BluetoothTestUtils extends Assert {
 
@@ -893,6 +894,17 @@
     }
 
     /**
+     * Deletes all pairings of remote devices
+     * @param adapter the BT adapter
+     */
+    public void unpairAll(BluetoothAdapter adapter) {
+        Set<BluetoothDevice> devices = adapter.getBondedDevices();
+        for (BluetoothDevice device : devices) {
+            unpair(adapter, device);
+        }
+    }
+
+    /**
      * Connects a profile from the local device to a remote device and checks to make sure that the
      * profile is connected and that the correct actions were broadcast.
      *
diff --git a/data/fonts/Android.mk b/data/fonts/Android.mk
index 0d9a386..97c1b33 100644
--- a/data/fonts/Android.mk
+++ b/data/fonts/Android.mk
@@ -133,6 +133,8 @@
     RobotoCondensed-Bold.ttf \
     RobotoCondensed-Italic.ttf \
     RobotoCondensed-BoldItalic.ttf \
+    RobotoCondensed-Light.ttf \
+    RobotoCondensed-LightItalic.ttf \
     DroidNaskh-Regular.ttf \
     DroidNaskhUI-Regular.ttf \
     DroidSansHebrew-Regular.ttf \
diff --git a/data/fonts/RobotoCondensed-Light.ttf b/data/fonts/RobotoCondensed-Light.ttf
new file mode 100644
index 0000000..41d212a
--- /dev/null
+++ b/data/fonts/RobotoCondensed-Light.ttf
Binary files differ
diff --git a/data/fonts/RobotoCondensed-LightItalic.ttf b/data/fonts/RobotoCondensed-LightItalic.ttf
new file mode 100755
index 0000000..dd54971
--- /dev/null
+++ b/data/fonts/RobotoCondensed-LightItalic.ttf
Binary files differ
diff --git a/data/fonts/fonts.mk b/data/fonts/fonts.mk
index 05cca13..293ecc8 100644
--- a/data/fonts/fonts.mk
+++ b/data/fonts/fonts.mk
@@ -32,6 +32,8 @@
     RobotoCondensed-Bold.ttf \
     RobotoCondensed-Italic.ttf \
     RobotoCondensed-BoldItalic.ttf \
+    RobotoCondensed-Light.ttf \
+    RobotoCondensed-LightItalic.ttf \
     DroidNaskh-Regular.ttf \
     DroidNaskhUI-Regular.ttf \
     DroidSansHebrew-Regular.ttf \
diff --git a/data/fonts/system_fonts.xml b/data/fonts/system_fonts.xml
index 549f061b..a8d23ee 100644
--- a/data/fonts/system_fonts.xml
+++ b/data/fonts/system_fonts.xml
@@ -65,6 +65,17 @@
             <file>RobotoCondensed-BoldItalic.ttf</file>
         </fileset>
     </family>
+
+    <family>
+        <nameset>
+            <name>sans-serif-condensed-light</name>
+        </nameset>
+        <fileset>
+            <file>RobotoCondensed-Light.ttf</file>
+            <file>RobotoCondensed-LightItalic.ttf</file>
+        </fileset>
+    </family>
+
     <family>
         <nameset>
             <name>serif</name>
diff --git a/data/keyboards/Generic.kl b/data/keyboards/Generic.kl
index ecd6a8b..1275939 100644
--- a/data/keyboards/Generic.kl
+++ b/data/keyboards/Generic.kl
@@ -161,8 +161,8 @@
 key 139   MENU              WAKE_DROPPED
 key 140   CALCULATOR
 # key 141 "KEY_SETUP"
-key 142   POWER             WAKE
-key 143   POWER             WAKE
+key 142   SLEEP             WAKE
+key 143   WAKEUP            WAKE
 # key 144 "KEY_FILE"
 # key 145 "KEY_SENDFILE"
 # key 146 "KEY_DELETEFILE"
@@ -425,3 +425,16 @@
 axis 0x0a BRAKE
 axis 0x10 HAT_X
 axis 0x11 HAT_Y
+
+# LEDs
+led 0x00 NUM_LOCK
+led 0x01 CAPS_LOCK
+led 0x02 SCROLL_LOCK
+led 0x03 COMPOSE
+led 0x04 KANA
+led 0x05 SLEEP
+led 0x06 SUSPEND
+led 0x07 MUTE
+led 0x08 MISC
+led 0x09 MAIL
+led 0x0a CHARGING
diff --git a/data/keyboards/Vendor_18d1_Product_2c40.kl b/data/keyboards/Vendor_18d1_Product_2c40.kl
new file mode 100644
index 0000000..903f13b6
--- /dev/null
+++ b/data/keyboards/Vendor_18d1_Product_2c40.kl
@@ -0,0 +1,42 @@
+# 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.
+
+# Odie
+
+key 304 BUTTON_A
+key 305 BUTTON_B
+key 307 BUTTON_X
+key 308 BUTTON_Y
+key 310 BUTTON_L1
+key 311 BUTTON_R1
+key 316 BUTTON_MODE
+key 317 BUTTON_THUMBL
+key 318 BUTTON_THUMBR
+
+key 158 BACK            WAKE_DROPPED
+key 172 HOME
+
+axis 0x00 X
+axis 0x01 Y
+axis 0x02 Z
+axis 0x05 RZ
+axis 0x09 RTRIGGER
+axis 0x0a LTRIGGER
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+led 0x00 CONTROLLER_1
+led 0x01 CONTROLLER_2
+led 0x02 CONTROLLER_3
+led 0x03 CONTROLLER_4
diff --git a/docs/html/_redirects.yaml b/docs/html/_redirects.yaml
index fc60e1f..58cf523 100644
--- a/docs/html/_redirects.yaml
+++ b/docs/html/_redirects.yaml
@@ -81,7 +81,7 @@
   to: /guide/components/aidl.html
 
 - from: /guide/publishing/publishing.html
-  to: /distribute/googleplay/publish/preparing.html
+  to: /distribute/tools/launch-checklist.html
 
 - from: /guide/publishing/...
   to: /tools/publishing/...
diff --git a/docs/html/about/dashboards/index.jd b/docs/html/about/dashboards/index.jd
index 6d29c69..c61a94b 100644
--- a/docs/html/about/dashboards/index.jd
+++ b/docs/html/about/dashboards/index.jd
@@ -1,4 +1,7 @@
 page.title=Dashboards
+page.metaDescription=page.metaDescription=Charts that give you an overview of device characteristics and platform versions that are active in the Android ecosystem.
+page.tags="android, dashboard, platforms, versions"
+meta.tags="ecosystem, versions, whatsnew"
 @jd:body
 
 <style>
@@ -22,7 +25,7 @@
 <div class="sidebox">
 <h2>Google Play Install Stats</h2>
 <p>The Google Play Developer Console also provides <a
-href="{@docRoot}distribute/googleplay/about/distribution.html#stats">detailed statistics</a>
+href="{@docRoot}distribute/googleplay/developer-console.html#app-stats">detailed statistics</a>
 about your users' devices. Those stats may help you prioritize the device profiles for which
 you optimize your app.</p>
 </div>
@@ -61,7 +64,7 @@
 </div>
 
 
-<p style="clear:both"><em>Data collected during a 7-day period ending on March 3, 2014.
+<p style="clear:both"><em>Data collected during a 7-day period ending on May 1, 2014.
 <br/>Any versions with less than 0.1% distribution are not shown.</em>
 </p>
 
@@ -92,7 +95,7 @@
 </div>
 
 
-<p style="clear:both"><em>Data collected during a 7-day period ending on March 3, 2014.
+<p style="clear:both"><em>Data collected during a 7-day period ending on May 1, 2014.
 <br/>Any screen configurations with less than 0.1% distribution are not shown.</em></p>
 
 
@@ -111,7 +114,7 @@
 
 
 <img alt="" style="float:right"
-src="//chart.googleapis.com/chart?chl=GL%201.1%20only%7CGL%202.0%7CGL%203.0&chf=bg%2Cs%2C00000000&chd=t%3A0.1%2C93.5%2C6.4&chco=c4df9b%2C6fad0c&chs=400x250&cht=p" />
+src="//chart.googleapis.com/chart?chs=400x250&cht=p&chd=t%3A0.1%2C87.0%2C12.9&chf=bg%2Cs%2C00000000&chl=GL%201.1%20only%7CGL%202.0%7CGL%203.0&chco=c4df9b%2C6fad0c" />
 
 <p>To declare which version of OpenGL ES your application requires, you should use the {@code
 android:glEsVersion} attribute of the <a
@@ -133,17 +136,17 @@
 </tr>
 <tr>
 <td>2.0</th>
-<td>91.1%</td>
+<td>87.0%</td>
 </tr>
 <tr>
 <td>3.0</th>
-<td>8.8%</td>
+<td>12.9%</td>
 </tr>
 </table>
 
 
 
-<p style="clear:both"><em>Data collected during a 7-day period ending on March 3, 2014</em></p>
+<p style="clear:both"><em>Data collected during a 7-day period ending on May 1, 2014</em></p>
 
 
 
@@ -161,17 +164,17 @@
 var VERSION_DATA =
 [
   {
-    "chart": "//chart.googleapis.com/chart?chl=Froyo%7CGingerbread%7CHoneycomb%7CIce%20Cream%20Sandwich%7CJelly%20Bean%7CKitKat&chd=t%3A1.2%2C19.0%2C0.1%2C15.2%2C62.0%2C2.5&chf=bg%2Cs%2C00000000&chco=c4df9b%2C6fad0c&chs=500x250&cht=p",
+    "chart": "//chart.googleapis.com/chart?chs=500x250&cht=p&chd=t%3A1.0%2C16.2%2C0.1%2C13.4%2C60.8%2C8.5&chf=bg%2Cs%2C00000000&chl=Froyo%7CGingerbread%7CHoneycomb%7CIce%20Cream%20Sandwich%7CJelly%20Bean%7CKitKat&chco=c4df9b%2C6fad0c",
     "data": [
       {
         "api": 8,
         "name": "Froyo",
-        "perc": "1.2"
+        "perc": "1.0"
       },
       {
         "api": 10,
         "name": "Gingerbread",
-        "perc": "19.0"
+        "perc": "16.2"
       },
       {
         "api": 13,
@@ -181,27 +184,27 @@
       {
         "api": 15,
         "name": "Ice Cream Sandwich",
-        "perc": "15.2"
+        "perc": "13.4"
       },
       {
         "api": 16,
         "name": "Jelly Bean",
-        "perc": "35.3"
+        "perc": "33.5"
       },
       {
         "api": 17,
         "name": "Jelly Bean",
-        "perc": "17.1"
+        "perc": "18.8"
       },
       {
         "api": 18,
         "name": "Jelly Bean",
-        "perc": "9.6"
+        "perc": "8.5"
       },
       {
         "api": 19,
         "name": "KitKat",
-        "perc": "2.5"
+        "perc": "8.5"
       }
     ]
   }
@@ -217,30 +220,29 @@
     "data": {
       "Large": {
         "hdpi": "0.6",
-        "ldpi": "0.7",
-        "mdpi": "4.3",
-        "tvdpi": "1.5",
+        "ldpi": "0.6",
+        "mdpi": "4.4",
+        "tvdpi": "1.6",
         "xhdpi": "0.6"
       },
       "Normal": {
-        "hdpi": "33.7",
-        "ldpi": "0.2",
-        "mdpi": "13.6",
+        "hdpi": "33.9",
+        "mdpi": "12.5",
         "xhdpi": "19.9",
-        "xxhdpi": "11.9"
+        "xxhdpi": "13.5"
       },
       "Small": {
-        "ldpi": "8.1"
+        "ldpi": "7.5"
       },
       "Xlarge": {
         "hdpi": "0.3",
         "ldpi": "0.1",
-        "mdpi": "4.3",
-        "xhdpi": "0.2"
+        "mdpi": "4.2",
+        "xhdpi": "0.3"
       }
     },
-    "densitychart": "//chart.googleapis.com/chart?chl=ldpi%7Cmdpi%7Ctvdpi%7Chdpi%7Cxhdpi%7Cxxhdpi&chd=t%3A9.1%2C22.2%2C1.5%2C34.6%2C20.7%2C11.9&chf=bg%2Cs%2C00000000&chco=c4df9b%2C6fad0c&chs=400x250&cht=p",
-    "layoutchart": "//chart.googleapis.com/chart?chl=Xlarge%7CLarge%7CNormal%7CSmall&chd=t%3A4.9%2C7.7%2C79.3%2C8.1&chf=bg%2Cs%2C00000000&chco=c4df9b%2C6fad0c&chs=400x250&cht=p"
+    "densitychart": "//chart.googleapis.com/chart?chs=400x250&cht=p&chd=t%3A8.2%2C21.1%2C1.6%2C34.8%2C20.8%2C13.5&chf=bg%2Cs%2C00000000&chl=ldpi%7Cmdpi%7Ctvdpi%7Chdpi%7Cxhdpi%7Cxxhdpi&chco=c4df9b%2C6fad0c",
+    "layoutchart": "//chart.googleapis.com/chart?chs=400x250&cht=p&chd=t%3A4.9%2C7.8%2C80.0%2C7.5&chf=bg%2Cs%2C00000000&chl=Xlarge%7CLarge%7CNormal%7CSmall&chco=c4df9b%2C6fad0c"
   }
 ];
 
diff --git a/docs/html/design/index.jd b/docs/html/design/index.jd
index 9ba32dd..cb7dd4f 100644
--- a/docs/html/design/index.jd
+++ b/docs/html/design/index.jd
@@ -1,4 +1,7 @@
 page.title=Design
+page.viewport_width=970
+section.landing=true
+meta.tags="beautifulapps, design, ux, patterns, holo, appquality, landing"
 header.hide=1
 footer.hide=1
 @jd:body
diff --git a/docs/html/design/media/dialogs_examples.png b/docs/html/design/media/dialogs_examples.png
index c136476..6ffcee2 100644
--- a/docs/html/design/media/dialogs_examples.png
+++ b/docs/html/design/media/dialogs_examples.png
Binary files differ
diff --git a/docs/html/design/media/navigation_drawer_titles_icons.png b/docs/html/design/media/navigation_drawer_titles_icons.png
index 7cf1e0c..902a72d 100644
--- a/docs/html/design/media/navigation_drawer_titles_icons.png
+++ b/docs/html/design/media/navigation_drawer_titles_icons.png
Binary files differ
diff --git a/docs/html/design/media/selection_adjusting_actions.png b/docs/html/design/media/selection_adjusting_actions.png
index 0799b6b..32a7fec 100644
--- a/docs/html/design/media/selection_adjusting_actions.png
+++ b/docs/html/design/media/selection_adjusting_actions.png
Binary files differ
diff --git a/docs/html/design/media/touch_feedback_communication.png b/docs/html/design/media/touch_feedback_communication.png
index f8162d0..1d4a9dc 100644
--- a/docs/html/design/media/touch_feedback_communication.png
+++ b/docs/html/design/media/touch_feedback_communication.png
Binary files differ
diff --git a/docs/html/design/media/ui_overview_notifications.png b/docs/html/design/media/ui_overview_notifications.png
index 6043412..7975657 100644
--- a/docs/html/design/media/ui_overview_notifications.png
+++ b/docs/html/design/media/ui_overview_notifications.png
Binary files differ
diff --git a/docs/html/design/patterns/multi-pane-layouts.jd b/docs/html/design/patterns/multi-pane-layouts.jd
index 6071ef3..08fa5bd 100644
--- a/docs/html/design/patterns/multi-pane-layouts.jd
+++ b/docs/html/design/patterns/multi-pane-layouts.jd
@@ -1,6 +1,7 @@
 page.title=Multi-pane Layouts
 page.tags="tablet","navigation","layout","fragment"
-page.metaDescription=Android devices come in many different screen sizes and types. Multi-pane layouts help you provide a balanced and aesthetically pleasing layout across the range of Android devices.
+page.metaDescription=Design guide with examples of how to flatten navigation and provide improved layout across the range of Android devices.
+
 @jd:body
 
 <a class="notice-developers" href="{@docRoot}training/basics/fragments/index.html">
diff --git a/docs/html/design/patterns/navigation.jd b/docs/html/design/patterns/navigation.jd
index 3e60f66..703528e 100644
--- a/docs/html/design/patterns/navigation.jd
+++ b/docs/html/design/patterns/navigation.jd
@@ -1,5 +1,6 @@
 page.title=Navigation with Back and Up
 page.tags="navigation","activity","task","up navigation","back navigation"
+page.image=/design/media/navigation_between_siblings_gmail.png
 @jd:body
 
 <a class="notice-developers" href="{@docRoot}training/implementing-navigation/index.html">
diff --git a/docs/html/design/patterns/widgets.jd b/docs/html/design/patterns/widgets.jd
index d08f178..47acc7b 100644
--- a/docs/html/design/patterns/widgets.jd
+++ b/docs/html/design/patterns/widgets.jd
@@ -1,5 +1,6 @@
 page.title=Widgets
 page.tags="appwidget","home"
+page.metaDescription=Design guide to creating widgets that are easy to use and look great.
 @jd:body
 
 <a class="notice-developers" href="{@docRoot}guide/topics/appwidgets/index.html">
diff --git a/docs/html/design/style/devices-displays.jd b/docs/html/design/style/devices-displays.jd
index a8f9d6f..6a7234b 100644
--- a/docs/html/design/style/devices-displays.jd
+++ b/docs/html/design/style/devices-displays.jd
@@ -1,7 +1,9 @@
 page.title=Devices and Displays
+page.metaDescription=Take advantage of Android's flexible layout system and create apps that gracefully scale from phones to tablets and beyond.
+
 @jd:body
 
-<p>Android powers millions of phones, tablets, and other devices in a wide variety of screen sizes and
+<p>Android powers hundreds of millions of phones, tablets, and other devices in a wide variety of screen sizes and
 form factors. By taking advantage of Android's flexible layout system, you can create apps that
 gracefully scale from large tablets to smaller phones.</p>
 
diff --git a/docs/html/design/style/metrics-grids.jd b/docs/html/design/style/metrics-grids.jd
index c375631..e92d57e 100644
--- a/docs/html/design/style/metrics-grids.jd
+++ b/docs/html/design/style/metrics-grids.jd
@@ -1,5 +1,8 @@
 page.title=Metrics and Grids
+page.metaDescription=Optimize your app's UI by designing layouts based on density-independent grids.
 page.tags="layout","screens"
+meta.tags="multiple screens, layout, tablets"
+page.image=/design/media/metrics_closeup.png
 @jd:body
 
 <p>Devices vary not only in physical size, but also in screen density (<acronym title="Dots per
diff --git a/docs/html/design/style/typography.jd b/docs/html/design/style/typography.jd
index 3c201f7..6923f0b 100644
--- a/docs/html/design/style/typography.jd
+++ b/docs/html/design/style/typography.jd
@@ -1,5 +1,6 @@
 page.title=Typography
 page.tags="textview","font"
+page.metaDescription=How to use typography in your Android apps.
 @jd:body
 
 <div class="layout-content-row">
diff --git a/docs/html/develop/index.jd b/docs/html/develop/index.jd
index 3f88b9d..bb90cca 100644
--- a/docs/html/develop/index.jd
+++ b/docs/html/develop/index.jd
@@ -1,5 +1,8 @@
 fullpage=true
-page.title=Develop
+page.title=Develop Apps
+page.viewport_width=970
+meta.tags="develop, getstarted, sdk, appquality, landing"
+section.landing=true
 header.hide=1
 carousel=1
 tabbedList=1
diff --git a/docs/html/distribute/distribute_toc.cs b/docs/html/distribute/distribute_toc.cs
deleted file mode 100644
index 1fabcb3..0000000
--- a/docs/html/distribute/distribute_toc.cs
+++ /dev/null
@@ -1,103 +0,0 @@
-<ul id="nav">
-
-  <li class="nav-section">
-    <div class="nav-section-header"><a href="<?cs var:toroot ?>distribute/index.html">Google Play</a></div>
-    <ul>
-      <li><a href="<?cs var:toroot ?>distribute/googleplay/about/visibility.html">Visibility</a></li>
-      <li><a href="<?cs var:toroot ?>distribute/googleplay/about/monetizing.html">Monetizing</a></li>
-      <li><a href="<?cs var:toroot ?>distribute/googleplay/about/distribution.html">Distribution</a></li>
-    </ul>  
-  </li>
-
-  <li class="nav-section">
-    <div class="nav-section-header"><a href="<?cs var:toroot ?>distribute/googleplay/publish/index.html">Publishing</a></div>
-    <ul>
-      <li><a href="<?cs var:toroot ?>distribute/googleplay/publish/register.html">Get Started</a></li>
-      <li><a href="<?cs var:toroot ?>distribute/googleplay/publish/console.html">Developer Console</a></li>
-      <li><a href="<?cs var:toroot ?>distribute/googleplay/publish/localizing.html">Localization Checklist</a></li>
-      <li><a href="<?cs var:toroot ?>distribute/googleplay/publish/preparing.html">Launch Checklist</a></li>
-    </ul>
-  </li>
-  
-<!--  <li class="nav-section">
-    <div class="nav-section-header">
-      <a href="<?cs var:toroot ?>distribute/googleplay/developer-console.html">The Developer Console</a>
-    </div>
-    <ul>
-      <li class="nav-section"><a href="<?cs var:toroot ?>distribute/googleplay/register.html">Get Started</a></li>
-      <li><a href="<?cs var:toroot ?>distribute/googleplay/distribution-controls.html">Managing Distribution</a></li>
-      <li><a href="<?cs var:toroot ?>distribute/googleplay/pricing-billing.html">Pricing and Billing</a></li>
-      <li><a href="<?cs var:toroot ?>distribute/googleplay/app-data.html">Reviewing App Data</a></li>
-      <li><a href="<?cs var:toroot ?>distribute/googleplay/advanced-options.html">Advanced Options</a></li>
-      <li><a href="<?cs var:toroot ?>distribute/googleplay/publishing.html">Publishing and Updating</a></li>
-    </ul>
-  </li> end of Developer Console -->
-
-   <li class="nav-section">
-     <div class="nav-section-header"><a href="<?cs var:toroot ?>distribute/googleplay/promote/index.html">Promoting</a>
-     </div>
-     <ul>
-<!--   <li><a href="<?cs var:toroot ?>distribute/googleplay/promote/product-pages.html">Your Product Pages</a></li> -->
-       <li><a href="<?cs var:toroot ?>distribute/googleplay/promote/linking.html">Linking to Your Products</a></li>
-       <li><a href="<?cs var:toroot ?>distribute/googleplay/promote/badges.html">Google Play Badges</a></li>
-       <li><a href="<?cs var:toroot ?>distribute/promote/device-art.html">Device Art Generator</a></li>
-       <li><a href="<?cs var:toroot ?>distribute/googleplay/promote/brand.html">Brand Guidelines</a></li>
-     </ul>
-   </li>
-
-  <li class="nav-section">
-    <div class="nav-section-header"><a href="<?cs var:toroot ?>distribute/googleplay/quality/index.html">App Quality</a></div>
-    <ul>
-       <li><a href="<?cs var:toroot ?>distribute/googleplay/quality/core.html">Core App Quality</a></li>
-       <li><a href="<?cs var:toroot ?>distribute/googleplay/quality/tablet.html">Tablet App Quality</a></li>
-       <li><a href="<?cs var:toroot ?>distribute/googleplay/strategies/app-quality.html">Improving App Quality</a></li>
-    </ul>
-  </li> 
-
-   <li class="nav-section">
-     <div class="nav-section-header"><a href="<?cs var:toroot ?>distribute/googleplay/policies/index.html">Policies</a></div>
-     <ul>
-       <li><a href="<?cs var:toroot ?>distribute/googleplay/policies/spam.html">Spam</a></li>
-       <li><a href="<?cs var:toroot ?>distribute/googleplay/policies/ip.html">Intellectual<br />Property</a></li> 
-       <li><a href="<?cs var:toroot ?>distribute/googleplay/policies/ads.html">Ads</a></li>
-     </ul>
-   </li>
-
-<!--    
-   <li class="nav-section">
-    <div class="nav-section-header"><a href="<?cs var:toroot ?>distribute/googleplay/after.html">
-      After Launch</a>
-    </div>
-    <ul>
-       <li><a href="<?cs var:toroot ?>distribute/googleplay/errors.html.html">Reviewing Errors</a></li>
-       <li><a href="<?cs var:toroot ?>distribute/googleplay/reviews.html">Tracking User Reviews</a></li>
-       <li><a href="<?cs var:toroot ?>distribute/googleplay/supporting-users.html">Supporting Users</a></li>
-    </ul>
-  </li> 
--->
-
-  <li class="nav-section">
-    <div class="nav-section-header"><a href="<?cs var:toroot ?>distribute/googleplay/spotlight/index.html">Spotlight</a></div>
-    <ul>
-       <li><a href="<?cs var:toroot ?>distribute/googleplay/spotlight/tablets.html">Tablet Stories</a></li>
-       <li><a href="<?cs var:toroot ?>distribute/googleplay/spotlight/games.html">Game Stories</a></li>
-       <li><a href="<?cs var:toroot ?>distribute/googleplay/spotlight/localization.html">Localization Stories</a></li>
-    </ul>
-  </li> 
-
-  <li class="nav-section">
-    <div class="nav-section-header"><a href="<?cs var:toroot ?>distribute/googleplay/edu/index.html">Google Play for Education</a></div>
-    <ul>
-      <li><a href="<?cs var:toroot ?>distribute/googleplay/edu/about.html">About</a></li>
-      <li><a href="<?cs var:toroot ?>distribute/googleplay/edu/start.html">Get Started</a></li>
-      <li><a href="<?cs var:toroot ?>distribute/googleplay/edu/guidelines.html">Guidelines</a></li>
-      <li><a href="<?cs var:toroot ?>distribute/googleplay/edu/faq.html">FAQ</a></li>
-      <li><a href="<?cs var:toroot ?>distribute/googleplay/edu/contact.html">Sign Up</a></li>
-    </ul>  
-  </li>
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="<?cs var:toroot ?>distribute/open.html">Open Distribution</a></div>
-  </li>
-</ul>
-  
\ No newline at end of file
diff --git a/docs/html/distribute/engage/app-updates.jd b/docs/html/distribute/engage/app-updates.jd
new file mode 100644
index 0000000..6b751b9
--- /dev/null
+++ b/docs/html/distribute/engage/app-updates.jd
@@ -0,0 +1,50 @@
+page.title=Update Your Apps Regularly
+page.metaDescription=Keeping your content fresh gives users a reason to come back.
+page.tags="updates"
+page.image=/images/gp-your-user-0.jpg
+
+@jd:body
+
+<p>
+  Keeping your content fresh gives users a reason to come back. Use any
+  <a href="{@docRoot}distribute/users/know-your-user.html#add-analytics">in-app
+  or game measurement tool</a> to keep an eye on what users respond to. Use
+  <a href=
+  "{@docRoot}distribute/googleplay/developer-console.html#alpha-beta">alpha-beta
+  testing</a> and <a href=
+  "{@docRoot}distribute/googleplay/developer-console.html#staged-rollouts">staged
+  rollouts</a> to quickly test new features, in-app content, and game
+  characters.
+</p>
+
+<p>
+  Updating regularly also gives you a chance to notify users about new content
+  should users lapse. Notification, email, and social media are several
+  channels to remind users to come back.
+</p>
+
+<p>
+  Check out the video below see how Kiwi uses frequent updates to engage and
+  retain users.
+</p>
+
+<p style="margin-bottom:2em">
+</p>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/engage/kiwi" data-sortorder="-timestamp" data-cardsizes=
+"18x6," data-maxresults="6">
+</div>
+
+<div class="headerLine clearfloat">
+  <h1 id="related-resources">
+    Related Resources
+  </h1>
+
+  <hr>
+</div>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/engage/appupdates" data-sortorder="-timestamp"
+data-cardsizes="9x3" data-maxresults="6">
+</div>
\ No newline at end of file
diff --git a/docs/html/distribute/engage/community.jd b/docs/html/distribute/engage/community.jd
new file mode 100644
index 0000000..035058a
--- /dev/null
+++ b/docs/html/distribute/engage/community.jd
@@ -0,0 +1,43 @@
+page.title=Engage Your Community
+page.metaDescription=Building a community has many benefits, including improving your app and bringing users back to it.
+page.image=/images/gp-engage-9.jpg
+
+
+@jd:body
+
+
+<div class="figure">
+  <img src="{@docRoot}images/gp-engage-9.jpg" style="width:300px;">
+</div>
+
+<p>
+  Building a community has many benefits, including improving your apps and
+  bringing users back to them. Using social media, groups, and forum tools will
+  help you build a rapport with your audience that will drive loyalty and
+  engagement.
+</p>
+
+<p>
+  There are many tactics to bring users back to your apps. In addition to app
+  updates that users want to check out, you can also use communities to
+  announce game tournaments, new content, promotions, and other great content.
+  Any reason to go back to your app is a great post to share with your
+  community.
+</p>
+
+<p>
+  Learn more about how to <a href="{@docRoot}distribute/users/build-community.html">build and manage a community</a>.
+</p>
+
+<div class="headerLine clearfloat">
+  <h1 id="related-resources">
+    Related Resources
+  </h1>
+
+  <hr>
+</div>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/engage/community" data-sortorder="-timestamp"
+data-cardsizes="9x3" data-maxresults="6">
+</div>
\ No newline at end of file
diff --git a/docs/html/distribute/engage/deep-linking.jd b/docs/html/distribute/engage/deep-linking.jd
new file mode 100644
index 0000000..cd62f9d
--- /dev/null
+++ b/docs/html/distribute/engage/deep-linking.jd
@@ -0,0 +1,78 @@
+page.title=Deep Link to Bring Users Back
+page.metaDescription=Use deep links to bring your users into your apps from social posts or search.
+page.tags="app indexing, google+ signin"
+page.image=/images/gp-listing-4.jpg
+
+@jd:body
+
+<p>
+  Use deep links to bring your users into your apps from social posts or
+  search.
+</p>
+
+<div class="headerLine">
+<h1>Deep Linking from Google+ Posts</h1><hr>
+</div>
+
+<p>
+  <a href="https://developers.google.com/+/mobile/android/share/deep-link">Deep
+  linking</a> allows the Google+ apps on mobile devices to direct clicks on a
+  shared post that contains deep-link information to a resource within your
+  apps.
+</p>
+
+<p style="margin-bottom:2em;">
+  If the user doesn’t have your app installed, they’re prompted to install it
+  before accessing the resource.
+</p>
+
+<div style="padding:2em, auto;width:550px;">
+  <div style="float:right; width:260px; padding-left:1em;">
+    <img src="{@docRoot}images/gp-engage-5.jpg" class="border-img">
+    <p class="img-caption">
+      G+ Post with Deep Link to Buy
+    </p>
+  </div>
+
+  <div style="width:260px;float:left;">
+    <img src="{@docRoot}images/gp-engage-6.jpg" class="border-img">
+    <p class="img-caption">
+      Purchase page within app
+    </p>
+  </div>
+</div>
+
+
+<div class="headerLine clearfloat">
+<h1>Deep Linking from Google Search &mdash; App Indexing</h1><hr>
+</div>
+
+<p>
+  Another way to bring users back to your apps is to apply for app indexing.
+</p>
+
+<p>
+  When a user searches for content available within your app, Google can show
+  an "Open in App" button in in mobile search results. For instance, if a user
+  searches for a restaurant and you’ve got that establishment in your dining
+  app, a link can be shown to open the page within your app. Learn more about
+  <a href="https://developers.google.com/app-indexing/">linking to in-app
+  content</a>.
+</p>
+
+<div>
+  <img src="{@docRoot}images/gp-listing-4.jpg" style="padding-top:1em;">
+</div>
+
+<div class="headerLine clearfloat">
+  <h1 id="related-resources">
+    Related Resources
+  </h1>
+
+  <hr>
+</div>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/engage/deeplinks" data-sortorder="-timestamp"
+data-cardsizes="9x3" data-maxresults="6">
+</div>
\ No newline at end of file
diff --git a/docs/html/distribute/engage/easy-signin.jd b/docs/html/distribute/engage/easy-signin.jd
new file mode 100644
index 0000000..92c3ffc
--- /dev/null
+++ b/docs/html/distribute/engage/easy-signin.jd
@@ -0,0 +1,103 @@
+page.title=Make Signing In Easy
+page.metaDescription=Increase conversion rates while helping users minimize typing by letting users sign in with Google+.
+page.tags="google+"
+page.image=/images/google/gps-googleplus.png
+
+
+@jd:body
+
+<div class="sidebox-wrapper" style="float:right;">
+  <div class="sidebox" style="width:360px;">
+    <p>
+      <strong>Tip:</strong> For game developers, Google+ signin is already
+      included as part of Google Play game services.
+    </p>
+  </div>
+</div>
+
+<p>
+  Increase conversion rates while helping users minimize typing by letting
+  users sign in with Google+. The <a href=
+  "{@docRoot}google/play-services/plus.html">Google+ platform for Android</a>
+  authenticates users with their Google credentials safely and securely. With
+  your <a href="https://developers.google.com/+/mobile/android/sign-in">users
+  signing in with Google</a>, you can create more engaging experiences and
+  drive the use of your apps .
+</p>
+
+<div style="width:450px;">
+  <img src="{@docRoot}images/google/gps-googleplus.png" style="padding-top:1em;">
+</div>
+
+<p>
+  Use the Google+ social graph to welcome users by name, display their
+  pictures, connect them with friends and more. Users authenticate once and
+  then are signed-in automatically when they come back, eliminating the need to
+  remember and type names and passwords.
+</p>
+
+<div class="headerLine">
+  <h1>
+    And Spreading the Word a Snap
+  </h1>
+
+  <hr>
+</div>
+
+
+<div class="figure" style="float:right;">
+  <img src="{@docRoot}images/gp-engage-share-plus.png" style=
+  "width:160px;padding-top:1em;">
+  <p class="img-caption">
+    Easy sharing through Google+
+  </p>
+</div>
+
+
+<p>
+  Using Google+ can help users spread the word about your apps to their
+  friends, attracting them to your apps, right from within your apps:
+</p>
+
+<p>
+  Google+ is also a great way to build a community of loyal fans that will help
+  you with <a href=
+  "https://support.google.com/googleplay/android-developer/answer/3131213">beta
+  testing</a>.
+</p>
+
+<ul>
+  <li>Using a <a href=
+  "https://developers.google.com/+/mobile/android/recommend">native +1
+  button</a> to let users make a recommendation for your apps or their content.
+  </li>
+
+  <li>
+    <a href="https://developers.google.com/+/mobile/android/share/">Share rich
+    content</a> to the Google+ stream, including text, photos, URL attachments,
+    and location.
+  </li>
+
+  <li>Create <a href=
+  "https://developers.google.com/+/mobile/android/share/interactive-post">Interactive
+  posts</a> to share your website or apps, users can even invite friends to
+  "listen," "RSVP," "check-in," or one of over 100 actions.
+  </li>
+</ul>
+
+  <div class="headerLine clearfloat">
+    <h1 id="related-resources">
+      Related Resources
+    </h1>
+
+    <hr>
+  </div>
+
+  <div class="resource-widget resource-flow-layout col-13"
+  data-query="collection:distribute/engage/gplus"
+  data-sortorder="-timestamp"
+  data-cardsizes="9x3"
+  data-maxresults="6">
+  </div>
+</div>
+
diff --git a/docs/html/distribute/engage/engage_toc.cs b/docs/html/distribute/engage/engage_toc.cs
new file mode 100644
index 0000000..0314f8c
--- /dev/null
+++ b/docs/html/distribute/engage/engage_toc.cs
@@ -0,0 +1,66 @@
+<ul id="nav">
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs
+        var:toroot?>distribute/engage/widgets.html">
+        <span class="en">Build Useful Widgets</span></a>
+    </div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs
+        var:toroot?>distribute/engage/notifications.html">
+        <span class="en">Use Rich Notifications</span></a>
+    </div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs
+        var:toroot?>distribute/engage/gcm.html">
+        <span class="en">Integrate GCM</span></a>
+    </div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs
+        var:toroot?>distribute/engage/easy-signin.html">
+        <span class="en">Make Signing In Easy</span></a>
+    </div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs
+        var:toroot?>distribute/engage/deep-linking.html">
+        <span class="en">Deep Link to Bring Users Back</span></a>
+    </div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs
+        var:toroot?>distribute/engage/game-services.html">
+        <span class="en">Encourage Competition</span></a>
+    </div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs
+        var:toroot?>distribute/engage/app-updates.html">
+        <span class="en">Update Regularly</span></a>
+    </div>
+  </li>
+
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs
+        var:toroot?>distribute/engage/community.html">
+        <span class="en">Engage Your Community</span></a>
+    </div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs
+        var:toroot?>distribute/engage/video.html">
+        <span class="en">Delight with Videos</span></a>
+    </div>
+  </li>
+
+</ul>
+
+<script type="text/javascript">
+<!--
+    buildToggleLists();
+    changeNavLang(getLangPref());
+//-->
+</script>
+
diff --git a/docs/html/distribute/engage/game-services.jd b/docs/html/distribute/engage/game-services.jd
new file mode 100644
index 0000000..5153435
--- /dev/null
+++ b/docs/html/distribute/engage/game-services.jd
@@ -0,0 +1,90 @@
+page.title=Encourage Competition
+page.metaDescription= Bring out the competitor in your users with cloud save, multiplayer game play, and more.
+page.tags="games"
+page.image=/images/google/gps-play_games_logo.png
+
+@jd:body
+
+<div class="figure" style="width:330px;">
+  <img src="{@docRoot}images/google/gps-play_games_logo.png">
+</div>
+
+<p>
+  Increase game installs, in-app revenue, and engagement with <a href=
+  "{@docRoot}google/play-services/games.html">Google Play
+  Game Services</a>. Bring out the competitor in your users with cloud save,
+  multiplayer game play, and more.
+</p>
+
+<ul>
+  <li>
+    <p>
+      <a href=
+      "https://developers.google.com/games/services/android/achievements">Achievements</a>
+      encourage players to try new features, resulting in more time spent in
+      your games.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      <a href=
+      "https://developers.google.com/games/services/android/leaderboards">Leaderboards</a>
+      are a fun way to drive competition among your players.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      <a href=
+      "https://developers.google.com/games/services/android/cloudsave">Cloud
+      Save</a> allows users to continue where they left off on another device
+      or platform.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Multiplayer features allow users to invite friends to install games and
+      play together in <a href=
+      "https://developers.google.com/games/services/common/concepts/realtimeMultiplayer">
+      real-time</a> or <a href=
+      "https://developers.google.com/games/services/common/concepts/turnbasedMultiplayer">
+      turn-by-turn</a>.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      <a href=
+      "https://play.google.com/store/apps/details?id=com.google.android.play.games">
+      Google Play Games App</a> provides additional exposure to increase
+      downloads and gameplay. It helps users play with friends, see what others
+      are playing, and discover featured games.
+    </p>
+  </li>
+</ul>
+
+<p>
+  And there is no need to worrying about device or OS version support. Google
+  Play Game Services is backward compatible, allowing you to reach more
+  users with less effort. Get started on <a href=
+  "{@docRoot}google/play-services/games.html">Google Play
+  Game Services</a>. For more tips on keeping gamers engaged, see the <a href=
+  "{@docRoot}distribute/essentials/best-practices/games.html">
+  Game Developer Best Practices</a>.
+</p>
+
+<div class="headerLine clearfloat">
+  <h1 id="related-resources">
+    Related Resources
+  </h1>
+
+  <hr>
+</div>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/engage/googleplaygames" data-sortorder="-timestamp"
+data-cardsizes="9x3" data-maxresults="6">
+</div>
+
diff --git a/docs/html/distribute/engage/gcm.jd b/docs/html/distribute/engage/gcm.jd
new file mode 100644
index 0000000..d793124e
--- /dev/null
+++ b/docs/html/distribute/engage/gcm.jd
@@ -0,0 +1,51 @@
+page.title=Integrate Google Cloud Messaging
+page.metaDescription=Keep your users in sync with your latest content by delivering lightweight messages over Google's infrastructure.
+page.tags="gcm"
+page.image=/images/gcm/gcm-logo.png
+
+@jd:body
+
+<div class="figure" style="width:330px">
+  <img src="{@docRoot}images/gcm/gcm-logo.png">
+</div>
+
+<p>
+  Keeping app content fresh is important to retaining users. And it’s easy with
+  the popular <a href="{@docRoot}google/gcm/index.html">Google Cloud
+  Messaging</a> for Android, by sending lightweight messages to your apps
+  installed on Android devices anywhere in the world.
+</p>
+
+<p>
+  Push messages from your backend servers to tell your apps that there's new
+  content for the user, or other data to sync.
+</p>
+
+<p>
+  You can use Google Cloud Messaging for two way messaging too. Another
+  possibility is to improve the experience for users with multiple devices, by
+  syncing content through the cloud so users have the same content on all their
+  devices.
+</p>
+
+<p>
+  Google Cloud Messaging lets your users stay in sync with your service without
+  draining the user’s battery, as there's no need for your apps poll a server
+  to discover new content. Best of all, Google Cloud Messaging is available for
+  free and there are no quotas.
+</p>
+
+<div class="headerLine clearfloat">
+  <h1 id="related-resources">
+    Related Resources
+  </h1>
+
+  <hr>
+</div>
+
+<div class="resource-widget resource-flow-layout col-13" 
+  data-query="collection:distribute/engage/gcm"
+  data-sortorder="-timestamp"
+  data-cardsizes="9x3"
+  data-maxresults="6">
+</div>
\ No newline at end of file
diff --git a/docs/html/distribute/engage/index.jd b/docs/html/distribute/engage/index.jd
new file mode 100644
index 0000000..f8cd1ee
--- /dev/null
+++ b/docs/html/distribute/engage/index.jd
@@ -0,0 +1,36 @@
+page.title=Engage & Retain Users
+page.metaDescription=Engaging and retaining active users is the key to success. Here are some resources to help you build an active user base.
+section.landing=true
+nonavpage=true
+
+@jd:body
+
+<p>
+  Engaging and retaining active users is the key to success. This is specially
+  true for subscription and in-app purchase models. Here are several tools and
+  techniques to keep your users coming back.
+</p>
+
+<div class="dynamic-grid">
+
+  <div class="resource-widget resource-flow-layout landing col-16"
+    data-query="collection:distribute/engagelanding"
+    data-cardSizes="6x6"
+    data-maxResults="9">
+  </div>
+
+  <h3>Related Resources</h3>
+  <div class="resource-widget resource-flow-layout col-16"
+    data-query="type:youtube+tag:engagement"
+    data-sortOrder="-timestamp"
+    data-cardSizes="6x3"
+    data-maxResults="3">
+  </div>
+  <div class="resource-widget resource-flow-layout col-16"
+    data-query="type:blog+tag:engagement"
+    data-sortdOrder="-timestamp"
+    data-cardSizes="6x3"
+    data-maxResults="3">
+  </div>
+
+</div>
\ No newline at end of file
diff --git a/docs/html/distribute/engage/notifications.jd b/docs/html/distribute/engage/notifications.jd
new file mode 100644
index 0000000..fecfb45
--- /dev/null
+++ b/docs/html/distribute/engage/notifications.jd
@@ -0,0 +1,61 @@
+page.title=Use Rich Notifications to Keep Users Informed
+page.metaDescription=Use Android's notifications to keep users in touch with your content and services &mdash; even when the app is not in use.
+page.tags=""
+page.image=/design/media/notifications_pattern_anatomy.png
+
+@jd:body
+
+<div class="figure">
+  <img src="{@docRoot}design/media/notifications_pattern_anatomy.png">
+</div>
+
+<p>
+  The <a href="/design/patterns/notifications.html">notification system</a>
+  allows your app to keep the user informed about events, such as new messages,
+  upcoming calendar appointments, shared photos, and much more. They are a
+  fundamental feature of Android that consumers check frequently to receive
+  important notifications and status updates. Notifications are like a news
+  channel that alerts the user to events as they happen and maintains a list of
+  updates since last review.
+</p>
+
+
+
+<p>
+  In addition to status updates from friends and family, notifications can also
+  be used to help gamers know when a time-based action is completed or another
+  player took their turn.</p>
+
+  <p>Some game developers use notifications to alert users
+  when a new limited time character can be won or a discount on an in-app
+  purchase is available. </p>
+
+<h3>But Use Them Sparingly</h3>
+
+<p>
+  Frequent notifications and spam notifications can turn users off, thereby
+  risking your ratings and user base. Also sure to check our <a href=
+  "https://support.google.com/googleplay/android-developer/answer/4430948">policies</a>
+  to ensure you’re treating your user respectfully.
+</p>
+
+
+  <div class="sidebox" style="width:326px;float:left;margin-left:0">
+          <p><strong>Tip:</strong>
+       Use notifications sparingly &mdash; be sure any information presented is
+      useful. Give users the option to turn notifications off.
+    </p>
+  </div>
+
+  <div class="headerLine clearfloat">
+  <h1 id="related-resources">
+    Related Resources
+  </h1><hr>
+</div>
+
+<div class="resource-widget resource-flow-layout col-13" 
+  data-query="collection:distribute/getusers/notifications"
+  data-sortorder="-timestamp"
+  data-cardsizes="9x3"
+  data-maxresults="6">
+</div>
\ No newline at end of file
diff --git a/docs/html/distribute/engage/video.jd b/docs/html/distribute/engage/video.jd
new file mode 100644
index 0000000..1a30f3a
--- /dev/null
+++ b/docs/html/distribute/engage/video.jd
@@ -0,0 +1,37 @@
+page.title=Delight Users with Videos
+page.metaDescription=Videos are one of the most effective ways to get users excited about your apps. 
+page.tags="engagement"
+page.image=/images/gp-engage-smule.jpg
+
+@jd:body
+<p>
+  Videos are one of the most effective ways to get users excited about your
+  apps. Use videos to showcase your apps on your Google Play Product Details
+  pages. Be sure to build a <a href="http://www.youtube.com/yt/dev/">YouTube</a>
+  page to host new videos so users can see new features or content that will
+  get them excited to return to your apps.
+</p>
+
+<p>
+  Videos let you do more than tell users about your apps &mdash; you can
+  <em>show them</em>. One of the most viewed content types is how-to videos.
+  Help users progress to the next level with YouTube <strong>game play
+  videos</strong> in Google Play, on your YouTube channel, and on your website.
+</p>
+
+<div class="center-img">
+  <img src="{@docRoot}images/gp-engage-smule.jpg">
+</div>
+
+<div class="headerLine clearfloat">
+  <h1 id="related-resources">
+    Related Resources
+  </h1>
+
+  <hr>
+</div>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/engage/video/more" data-sortorder="-timestamp"
+data-cardsizes="9x3" data-maxresults="6">
+</div>
\ No newline at end of file
diff --git a/docs/html/distribute/engage/widgets.jd b/docs/html/distribute/engage/widgets.jd
new file mode 100644
index 0000000..b17af08
--- /dev/null
+++ b/docs/html/distribute/engage/widgets.jd
@@ -0,0 +1,42 @@
+page.title=Build Useful Widgets
+page.metaDescription=Use widgets to remind users about important information in your apps and games, even when your apps are closed.
+page.tags=""
+page.image=/images/gp-engage-0.jpg
+
+@jd:body
+
+<div class="figure">
+  <img src="{@docRoot}images/gp-engage-0.jpg" style="width:320px;">
+</div>
+<p>
+  <a href=
+  "/design/patterns/widgets.html">Widgets</a> are
+  an essential aspect of home screen customization. They are "at-a-glance"
+  views of an app's <strong>most important data and features</strong>,
+  instantly available from the user's home screen.
+</p>
+
+<p>
+  Use widgets to <strong>remind users</strong> about important information in
+  your apps and games, even when your apps are closed. For instance, if you
+  have a news app, showcase the latest headlines.
+</p>
+
+  <div class="sidebox" style="float:none;margin-left:0">
+  <p><strong>Tip:</strong>
+  Make your widgets useful &mdash; provide in-app information like news, game status,
+  or upcoming deadlines. Widgets should serve as more than a launcher icon.</p>
+  </div>
+
+<div class="headerLine clearfloat">
+  <h1 id="related-resources">
+    Related Resources
+  </h1><hr>
+</div>
+
+<div class="resource-widget resource-flow-layout col-13" 
+  data-query="collection:distribute/engage/widgets"
+  data-sortorder="-timestamp"
+  data-cardsizes="9x3"
+  data-maxresults="6">
+</div>
\ No newline at end of file
diff --git a/docs/html/distribute/essentials/best-practices/apps.jd b/docs/html/distribute/essentials/best-practices/apps.jd
new file mode 100644
index 0000000..055a349
--- /dev/null
+++ b/docs/html/distribute/essentials/best-practices/apps.jd
@@ -0,0 +1,260 @@
+page.title=App Developer Best Practices
+page.image=/distribute/images/gp-app-practices.png
+page.metaDescription=Essential tips for launching successful apps in Google Play.
+@jd:body
+
+<div id="qv-wrapper"><div id="qv">
+<h2>Best Practices</h2>
+<ol>
+<li><a href="#essentials">Get the Essentials Right</a></li>
+<li><a href="#users">Get Users</a></li>
+<li><a href="#engage">Engage and Retain</a></li>
+<li><a href="#beyond">Beyond the Basics</a></li>
+<li><a href="#related-resources">Related Resources</a></li>
+</ol>
+</div></div>
+
+<p>The following best practices have enabled developers worldwide to build great, successful apps for Google Play.</p>
+
+<div class="headerLine">
+<h1 id="essentials">Get the Essentials Right</h1><hr>
+</div>
+
+<h3>1. Make it Android</h3>
+
+<ul>
+  <li>
+  <p>
+    Build your apps to make best use of the unique Android features, such as
+    <a href="{@docRoot}distribute/engage/widgets.html">widgets</a>, <a href=
+    "{@docRoot}distribute/engage/notifications.html">rich notifications</a>,
+    <a href=
+    "http://android-developers.blogspot.com/2012/02/share-with-intents.html">sharing
+    through Intents</a>, and more.
+  </p>
+  </li>
+
+  <li>
+  <p>
+    Add the power of Google features your users already love, such as
+    <a href="https://developers.google.com/maps/documentation/android/">Google
+    Maps</a>, <a href="https://developers.google.com/drive/">Google
+    Drive</a>, and more, all with <a href=
+    "https://developers.google.com/+/mobile/android/sign-in">single sign
+    on</a>.
+  </p>
+  </li>
+</ul>
+
+<h3>
+  2. Make it quality
+</h3>
+
+<ul>
+  <li>
+  <p>
+    Make sure your apps follow the <a href=
+    "{@docRoot}distribute/essentials/quality/core.html">Core App Quality</a>
+    guidelines.
+  </p>
+  </li>
+
+  <li>
+  <p>
+    Create apps that are available on all form factors and screen sizes, by
+    following the <a href=
+    "{@docRoot}distribute/essentials/quality/tablets.html">Tablet App
+    Quality</a> guidelines.
+  </p>
+  </li>
+
+  <li>
+  <p>
+    Test and <a href=
+    "{@docRoot}distribute/essentials/optimizing-your-app.html">optimize your
+    quality</a> at every step and make use of the Google Play <a href=
+    "{@docRoot}distribute/googleplay/developer-console.html#alpha-beta">beta-testing</a>
+    and <a href=
+    "{@docRoot}distribute/googleplay/developer-console.html#staged-rollouts">staged
+    rollouts</a> features to test with users before launch.
+  </p>
+  </li>
+</ul>
+
+<div class="headerLine">
+  <h1 id="users">
+  Get Users
+  </h1>
+
+  <hr>
+</div>
+
+<h3>
+  1. Build buzz
+</h3>
+
+<ul>
+  <li>
+  <p>
+    Create a great <a href="{@docRoot}distribute/users/your-listing.html">app
+    listing page</a> to showcase your apps and grab users’ attention. Don’t
+    forget to include a <a href=
+    "{@docRoot}distribute/engage/video.html">YouTube video</a>.
+  </p>
+  </li>
+
+  <li>
+  <p>
+    <a href="{@docRoot}distribute/tools/launch-checklist.html">Launch</a> on
+    multiple platforms simultaneously to maximize your reach.
+  </p>
+  </li>
+
+  <li>
+  <p>
+    Promote your apps with the official <a href=
+    "{@docRoot}distribute/tools/promote/badges.html">Google Play badge</a>
+    and <a href="{@docRoot}distribute/tools/promote/linking.html">link to
+    your products</a> on Google Play.
+  </p>
+  </li>
+
+  <li>
+  <p>
+    Build a community with social media, <a href=
+    "http://groups.google.com/">forums</a>, and <a href=
+    "http://plus.google.com">communities</a> to get and keep users talking.
+  </p>
+  </li>
+</ul>
+
+<h3>
+  2. Optimize for great ratings
+</h3>
+
+<ul>
+  <li>
+  <p>
+    Get to <a href="{@docRoot}distribute/users/know-your-user.html">know your
+    users</a>, listen to and <a href=
+    "{@docRoot}distribute/engage/app-updates.html">update your apps</a> from
+    their feedback.
+  </p>
+  </li>
+
+  <li>
+  <p>
+    Focus on your strength markets first, get these right before expanding.
+  </p>
+  </li>
+</ul>
+
+<div class="headerLine">
+  <h1 id="engage">
+  Engage and Retain
+  </h1>
+
+  <hr>
+</div>
+
+<h3>
+  1. Keep users coming back
+</h3>
+
+<ul>
+  <li>
+  <p>
+    Use <a href="{@docRoot}google/play/billing/index.html">Google Play In-app
+    Billing</a> to offer subscriptions to extended features.
+  </p>
+  </li>
+
+  <li>
+  <p>
+    Hold competitions and offer promotions, then announce them through
+    <a href="{@docRoot}design/patterns/notifications.html">notifications</a>.
+  </p>
+  </li>
+</ul>
+
+<h3>
+  2. Earn users’ love
+</h3>
+
+<ul>
+  <li>
+  <p>
+    <a href=
+    "http://android-developers.blogspot.com/2013/05/all-google-play-developers-can-now.html">
+    Respond to reviews</a> and get valuable feedback from the community
+    you've built.
+  </p>
+  </li>
+
+  <li>
+  <p>
+    <a href=
+    "http://android-developers.blogspot.com/2013/10/improved-app-insight-by-linking-google.html">
+    Measure</a> your campaigns to see what is driving users to install your
+    apps.
+  </p>
+  </li>
+
+  <li>
+  <p>
+    <a href=
+    "{@docRoot}distribute/essentials/optimizing-your-app.html#measuring-analyzing-responding">
+    Analyze in-app use</a> to steer content updates and prolong the life of
+    your apps.
+  </p>
+  </li>
+</ul>
+
+<div class="headerLine">
+  <h1 id="beyond">
+  Beyond the Basics
+  </h1>
+
+  <hr>
+</div>
+
+<ul>
+  <li>
+  <p>
+    After you’ve launched in your market of strength, <a href=
+    "{@docRoot}distribute/users/expand-to-new-markets.html">expand into other
+    markets</a> strategically and <a href=
+    "{@docRoot}distribute/tools/localization-checklist.html">localize</a>
+    your apps as you go.
+  </p>
+  </li>
+
+  <li>
+  <p>
+    Keep users engaged, and stay ahead of the competition, by continually
+    <a href=
+    "{@docRoot}distribute/essentials/optimizing-your-app.html">optimizing
+    your apps</a> to offer new and better features, or retire those that
+    users aren’t using.
+  </p>
+  </li>
+
+  <li>
+  <p>
+    Build educational apps: learn <a href=
+    "{@docRoot}distribute/googleplay/edu/start.html">how to make apps for
+    Google Play for Education</a>.
+  </p>
+  </li>
+</ul>
+
+<div class="headerLine">
+<h1 id="related-resources">Related Resources</h1><hr>
+</div>
+
+<div class="resource-widget resource-flow-layout col-13"
+  data-query="collection:distribute/toolsreference/bestpractices/apps"
+  data-sortOrder="-timestamp"
+  data-cardSizes="9x3,9x3"
+  data-maxResults="6"></div>
+
diff --git a/docs/html/distribute/essentials/best-practices/games.jd b/docs/html/distribute/essentials/best-practices/games.jd
new file mode 100644
index 0000000..ac1df44
--- /dev/null
+++ b/docs/html/distribute/essentials/best-practices/games.jd
@@ -0,0 +1,259 @@
+page.title=Game Developer Best Practices
+page.image=/distribute/images/gp-games-practices.png
+page.metaDescription=Essential tips for launching successful games in Google Play.
+
+@jd:body
+
+<div id="qv-wrapper"><div id="qv">
+<h2>Best Practices</h2>
+<ol>
+<li><a href="#users">Get Users</a></li>
+<li><a href="#engage">Engage and Retain</a></li>
+<li><a href="#beyond">Beyond the Basics</a></li>
+<li><a href="#related-resources">Related Resources</a></li>
+</ol>
+</div></div>
+
+<p>
+  The following best practices have enabled developers worldwide to build
+  great, successful games for Google Play.
+</p>
+
+<div class="headerLine">
+  <h1 id="users">
+  Get Users
+  </h1>
+
+  <hr>
+</div>
+
+<h3>
+  1. Optimize for great ratings
+</h3>
+
+<ul>
+  <li>
+  <p>
+    <a href=
+    "{@docRoot}distribute/googleplay/developer-console.html#alpha-beta">Beta
+    test</a> to ensure your games are ready and poised for great ratings.
+  </p>
+  </li>
+
+  <li>
+  <p>
+    Optimize graphics, frame rates, and responsiveness with the <a href=
+    "http://android-developers.blogspot.com/2013/09/using-hardware-scaler-for-performance.html">
+    Hardware Scaler</a> and <a href=
+    "{@docRoot}training/graphics/opengl/index.html">OpenGL ES</a>.
+  </p>
+  </li>
+
+  <li>
+  <p>
+    Be sure your APK is small, then provide game content through over-the-air
+    downloads.
+  </p>
+  </li>
+</ul>
+
+<h3>
+  2. Build buzz
+</h3>
+
+<ul>
+  <li>
+  <p>
+    Build a community with social media, <a href=
+    "{@docRoot}distribute/users/build-community.html">communities</a> to get
+    and keep users talking.
+  </p>
+  </li>
+
+  <li>
+  <p>
+    Promote your games with official <a href=
+    "{@docRoot}distribute/tools/promote/badges.html">Google Play badges</a>
+    and <a href="{@docRoot}distribute/tools/promote/linking.html">links to
+    your products</a> on Google Play.
+  </p>
+  </li>
+
+  <li>
+  <p>
+    If you ship on multiple platforms, doing so at the same time can maximize
+    your marketing impact.
+  </p>
+  </li>
+</ul>
+
+<h3>
+  3. Get Visibility
+</h3>
+
+<ul>
+  <li>
+  <p>
+    First impressions count: <a href=
+    "{@docRoot}distribute/users/your-listing.html">highlight</a> the game's
+    best features in screenshots, videos, and description.
+  </p>
+  </li>
+
+  <li>
+  <p>
+    Integrate Google Play Game Services, so your game is displayed in the
+    <a href=
+    "https://play.google.com/store/apps/details?id=com.google.android.play.games">
+    Google Play Games App</a>.
+  </p>
+  </li>
+</ul>
+
+<div class="headerLine">
+  <h1 id="engage">
+  Engage and Retain
+  </h1>
+
+  <hr>
+</div>
+
+<h3>
+  1. Keep users coming back
+</h3>
+
+<ul>
+  <li>
+  <p>
+    <a href=
+    "https://developers.google.com/games/services/common/concepts/achievements">
+    Achievements</a>, <a href=
+    "https://developers.google.com/games/services/common/concepts/leaderboards">
+    leaderboards</a>, <a href=
+    "https://developers.google.com/games/services/common/concepts/realtimeMultiplayer">
+    multiplayer</a>, and <a href=
+    "https://developers.google.com/games/services/common/concepts/cloudsave">cloud
+    save</a> help engage users and bring them back.
+  </p>
+  </li>
+
+  <li>
+  <p>
+    Hold tournaments and offer promotions, then announce them through
+    <a href="{@docRoot}design/patterns/notifications.html">notifications</a>.
+  </p>
+  </li>
+
+  <li>
+  <p>
+    Sign in users early, then automatically. Before their first sign-in, save
+    progress locally.
+  </p>
+  </li>
+</ul>
+
+<h3>
+  2. Give users a reason to invest their money
+</h3>
+
+<ul>
+  <li>
+  <p>
+    A majority of the top grossing games use in-app purchases. Use them to
+    unlock content and allow players to enhance their game play.
+  </p>
+  </li>
+
+  <li>
+  <p>
+    <a href="{@docRoot}google/play/billing/index.html">Google Play In-app
+    Billing</a> makes purchasing easy with several forms of payment.
+  </p>
+  </li>
+
+  <li>
+  <p>
+    Provide content updates regularly to give users limited edition items to
+    win or purchase.
+  </p>
+  </li>
+</ul>
+
+<h3>
+  3. Earn players’ love
+</h3>
+
+<ul>
+  <li>
+  <p>
+    <a href=
+    "http://android-developers.blogspot.com/2013/10/improved-app-insight-by-linking-google.html">
+    Measure</a> your campaigns to see what’s driving quality users to install
+    your games.
+  </p>
+  </li>
+
+  <li>
+  <p>
+    <a href=
+    "{@docRoot}distribute/essentials/optimizing-your-app.html#measuring-analyzing-responding">
+    Analyze in-game use</a> to steer content updates and prolong the life of your
+    games.
+  </p>
+  </li>
+
+  <li>
+  <p>
+    <a href=
+    "http://android-developers.blogspot.com/2013/05/all-google-play-developers-can-now.html">
+    Respond to reviews</a> and get valuable feedback from the community
+    you’ve built.
+  </p>
+  </li>
+</ul>
+
+<div class="headerLine">
+  <h1 id="beyond">
+  Beyond the Basics
+  </h1>
+
+  <hr>
+</div>
+
+<ul>
+  <li>
+  <p>
+    After you've launched in your market of strength, <a href=
+    "{@docRoot}distribute/users/expand-to-new-markets.html">expand into other
+    markets</a> strategically and <a href=
+    "{@docRoot}distribute/tools/localization-checklist.html">localize</a>
+    your apps as you go.
+  </p>
+  </li>
+
+  <li>
+  <p>
+    Provide content <a href=
+    "{@docRoot}distribute/engage/app-updates.html">updates on a regular
+    basis</a> to keep users engaged.
+  </p>
+  </li>
+
+  <li>
+  <p>
+    Building educational games? See the <a href=
+    "{@docRoot}distribute/essentials/gpfe-guidelines.html">Education
+    Guidelines</a>.
+  </p>
+  </li>
+</ul>
+
+<div class="headerLine">
+<h1 id="related-resources">Related Resources</h1><hr>
+</div>
+
+<div class="resource-widget resource-flow-layout col-13"
+  data-query="collection:distribute/toolsreference/bestpractices/games"
+  data-sortOrder="-timestamp"
+  data-cardSizes="9x3,9x3"
+  data-maxResults="6"></div>
diff --git a/docs/html/distribute/essentials/essentials_toc.cs b/docs/html/distribute/essentials/essentials_toc.cs
new file mode 100644
index 0000000..7084fdd
--- /dev/null
+++ b/docs/html/distribute/essentials/essentials_toc.cs
@@ -0,0 +1,44 @@
+<ul id="nav">
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/essentials/quality/core.html">
+            <span class="en">Core App Quality</span></a>
+    </div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/essentials/quality/tablets.html">
+            <span class="en">Tablet App Quality</span>
+          </a>
+    </div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/essentials/gpfe-guidelines.html">
+          <span class="en">Education Guidelines</span>
+        </a>
+    </div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/essentials/optimizing-your-app.html">
+          <span class="en">Optimize Your App</span>
+        </a>
+    </div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/essentials/best-practices/apps.html">
+          <span class="en">App Best Practices</span>
+        </a>
+    </div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/essentials/best-practices/games.html">
+          <span class="en">Game Best Practices</span>
+        </a>
+    </div>
+  </li>
+
+
+<script type="text/javascript">
+<!--
+    buildToggleLists();
+    changeNavLang(getLangPref());
+//-->
+</script>
diff --git a/docs/html/distribute/essentials/gpfe-guidelines.jd b/docs/html/distribute/essentials/gpfe-guidelines.jd
new file mode 100644
index 0000000..8b47671
--- /dev/null
+++ b/docs/html/distribute/essentials/gpfe-guidelines.jd
@@ -0,0 +1,513 @@
+page.title=Education Guidelines
+page.metaDescription=These guidelines and requirements help you develop great apps for students, which offer compelling content and an intuitive user experience on Android tablets.
+page.image=/distribute/images/edu-guidelines.jpg
+Xnonavpage=true
+
+@jd:body
+
+
+<div id="qv-wrapper"><div id="qv">
+<h2>Guidelines</h2>
+<ol>
+<li><a href="#basic-reqts">Basic Requirements</a></li>
+<li><a href="#monetizing-ads">Monetizing and Ads</a></li>
+<li><a href="#e-value">Educational Value</a></li>
+<li><a href="#quality">App Quality</a></li>
+<li><a href="#related-resources">Related Resources</a></li>
+</ol>
+
+<h2>
+  Testing
+</h2>
+
+<ol>
+  <li>
+    <a href="#test-environment">Setting Up a Test Environment</a>
+  </li>
+</ol>
+
+</div></div>
+
+<div style="margin:0 0 1em 0;">
+  <img src="{@docRoot}distribute/images/edu-guidelines.jpg" style=
+  "width:274px;">
+</div>
+
+<p>
+  These guidelines and requirements help you develop great apps for students,
+  which offer compelling content and an intuitive user experience on Android
+  tablets.
+</p>
+
+<p>
+  You’ll also need to ensure that your apps comply with the terms of the
+  <a href=
+  "https://play.google.com/about/developer-distribution-agreement-addendum.html">
+  Google Play for Education Addendum</a>, <a href=
+  "http://play.google.com/about/developer-content-policy.html">Google Play
+  Developer Program Policies</a>, and <a href=
+  "http://play.google.com/about/developer-distribution-agreement.html">Developer
+  Distribution Agreement</a>.
+</p>
+
+<div class="headerLine clearfloat">
+  <h1 id="basic-reqts">
+    Basic Requirements
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  To participate, your apps must be designed for the K-12 market. The basic
+  requirements that your apps must meet are:
+</p>
+
+<ul>
+  <li>
+    <p>
+      Apps and the ads they contain must not collect personally identifiable
+      information, other than user credentials or data required to operate and
+      improve the app.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Apps must not use student data for purposes unrelated to its educational
+      function.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Apps must have a content rating of "Everyone" or "Low Maturity" (apps
+      with a "Medium Maturity" rating are allowed, if they have that rating
+      solely because they allow communication between students).
+    </p>
+  </li>
+
+  <li>
+    <p>
+      App content, including ads displayed by the app, must be consistent with
+      the app's maturity rating. The app must not display any "offensive"
+      content, as described in the <a href=
+      "http://play.google.com/about/developer-content-policy.html">Google Play
+      Developer Program Policies</a> and <a href=
+      "https://support.google.com/googleplay/android-developer/answer/188189">content-rating
+      guidelines</a>.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Apps must comply with the Children’s Online Privacy Protection Act and
+      all other applicable laws and regulations.
+    </p>
+  </li>
+</ul>
+
+<div class="headerLine">
+  <h1 id="monetizing-ads">
+    Monetizing and Ads
+  </h1>
+
+  <hr>
+</div>
+
+<div class="figure">
+  <img src="{@docRoot}images/gp-edu-monetize.png">
+</div>
+
+<p>
+  In-app purchase is currently not supported with Google Play for Education, so
+  a student device will block any transactions. To avoid confusion, be sure to
+  remove any in-app purchase buttons and related UI elements from your apps.
+  We’re investigating additional purchase mechanisms to enable more flexible
+  pricing models for developers and schools.
+</p>
+
+<p>
+  If your apps are priced In Google Play for Education, you must allow Google
+  Play to offer teachers limited free trials before purchase (you provide this
+  through business terms only, no development work is needed.)
+</p>
+
+<p>
+  You can only choose not to remove in-app purchasing from your apps where all
+  content and services are sold through Google Play for Education using In-app
+  Billing. If you choose not to remove In-app Billing features, ensure that:
+</p>
+
+<ul>
+  <li>
+    <p>
+      Users can access your apps’ core functionality for a classroom setting
+      without an in-app purchase.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      In-app purchases are clearly identifiable in your UI.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      You declare the use of in-app purchases at <a href=
+      "{@docRoot}distribute/googleplay/edu/start.html#publish">opt-in</a>.
+    </p>
+  </li>
+</ul>
+
+<p>
+  For each app that you publish, you can set a single price that applies to
+  both Google Play and Google Play for Education. You can’t set a different
+  price for a given app (based on a single package name) in Google Play for
+  Education.
+</p>
+
+<p>
+  If your apps display ads, you should disable the display of ads if possible,
+  or ensure that:
+</p>
+
+<ul>
+  <li>Ads are not distracting for students or teachers (this includes
+  Flash-based ads, video ads, and ads that flash or move)
+  </li>
+
+  <li>Interstitial ads are not served in the app
+  </li>
+
+  <li>Ad walls do not appear in the app UI
+  </li>
+
+  <li>Ads do not occupy a significant portion of the screen
+  </li>
+
+  <li>Ads content does not exceed the maturity rating of the app.
+  </li>
+
+  <li>
+    <p>
+      You declare the use of ads at <a href=
+      "{@docRoot}distribute/googleplay/edu/start.html#publish">opt-in</a>.
+    </p>
+  </li>
+</ul>
+
+<div class="headerLine">
+  <h1 id="e-value">
+    Educational Value
+  </h1>
+
+  <hr>
+</div>
+
+<div class="figure">
+  <img src="{@docRoot}images/gp-e-value.png" class="border-img">
+</div>
+
+<p>
+  Apps submitted to Google Play for Education will be evaluated by a
+  third-party educator network, which will review them based on alignment with
+  <a href="http://www.corestandards.org/">Common Core Standards</a> and other
+  educational considerations. This will help make your content more
+  discoverable for teachers and administrators as they browse by grade level,
+  subject, core curriculum, and other parameters.
+</p>
+
+<p>
+  Apps with highest educational value will have these characteristics:
+</p>
+
+<ul>
+  <li>
+    <p>
+      Designed for use in K-12 classrooms.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Aligned with a common core standard or support common-core learning.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Simple, easy to use, and intuitive for the grade levels the apps are
+      targeting. Apps are relatively easy to navigate without teacher guidance.
+      Not distracting or overwhelming to students.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Enjoyable and interactive. Apps are engaging to students and lets them
+      control their experience.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Versatile. Apps have features that make them useful for more than one
+      classroom function or lesson throughout the school year.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Supports the "4Cs":
+    </p>
+
+    <ul>
+      <li>
+        <p>
+          <em>Creativity</em> &mdash; Allows students to create in order to
+          express understanding of the learning objectives, and try new
+          approaches, innovation, and invention to get things done.
+        </p>
+      </li>
+
+      <li>
+        <p>
+          <em>Critical thinking</em> &mdash; Allows students to look at
+          problems in a new way, linking learning across subjects and
+          disciplines.
+        </p>
+      </li>
+
+      <li>
+        <p>
+          <em>Collaboration</em> &mdash; Allows students and (if appropriate)
+          educators to work together to reach a goal.
+        </p>
+      </li>
+
+      <li>
+        <p>
+          <em>Communication</em> &mdash; Allows students to comprehend,
+          critique and share thoughts, questions, ideas, and solutions.
+        </p>
+      </li>
+    </ul>
+  </li>
+</ul>
+
+<p>
+  As you design and develop your apps, make sure they offer high educational
+  value by addressing as many of these characteristics as possible.
+</p>
+
+<div class="headerLine">
+  <h1 id="quality">
+    App Quality
+  </h1>
+
+  <hr>
+</div>
+
+<div class="figure">
+  <img src="{@docRoot}images/gp-edu-quality.png">
+</div>
+
+<p>
+  Your apps should be designed to perform well and look great on Android
+  tablets, and they should offer the best user experience possible.
+</p>
+
+<p>
+  High quality apps are engaging, intuitive, and offer compelling content.
+  Google Play for Education will highlight high-quality apps for easy discovery
+  in the store. Here are some recommendations for making your app easy for
+  students and teachers to enjoy:
+</p>
+
+<ul>
+  <li>
+    <p>
+      Meet the Core Quality Guidelines:
+    </p>
+
+    <ul>
+      <li>
+        <p>
+          Follow <a href="{@docRoot}design/index.html">Android Design
+          Guidelines</a>. Pay special attention to the sections on <a href=
+          "{@docRoot}design/patterns/actionbar.html">Action Bar</a>, <a href=
+          "{@docRoot}design/patterns/navigation.html">Navigation</a>, and
+          <a href="{@docRoot}design/patterns/pure-android.html">Pure
+          Android</a>.
+        </p>
+      </li>
+
+      <li>
+        <p>
+          Test your apps against the <a href=
+          "{@docRoot}distribute/essentials/quality/core.html">Core Quality
+          Guidelines</a>.
+        </p>
+      </li>
+    </ul>
+  </li>
+
+  <li>
+    <p>
+      Meet the Tablet App Quality guidelines:
+    </p>
+
+    <ul>
+      <li>
+        <p>
+          Follow our best practices for tablet app development.
+        </p>
+      </li>
+
+      <li>
+        <p>
+          Review the <a href=
+          "{@docRoot}distribute/essentials/quality/tablets.html">Tablet App
+          Quality</a> guidelines and <a href=
+          "http://android-developers.blogspot.com/2012/11/designing-for-tablets-were-here-to-help.html">
+          blog post on designing for tablets.</a>
+        </p>
+
+        <ul>
+          <li>Check your Optimization Tips in the <a href=
+          "https://play.google.com/apps/publish/">Developer Console</a> (if
+          you've already uploaded your apps.)
+          </li>
+        </ul>
+      </li>
+
+      <li>
+        <p>
+          Strive for simplicity and highest usability for students:
+        </p>
+
+        <ul>
+          <li>
+            <p>
+              Design your app so that teachers and students can use all the
+              capabilities of your app without having to sign-in to multiple
+              accounts and remember multiple passwords.
+            </p>
+          </li>
+
+          <li>
+            <p>
+              Every student or teacher using a Google Play for Education tablet
+              will already be signed in with a Google account on the device.
+              You can take advantage of that to provide a simple, seamless
+              sign-in experience in your app. A recommended approach is to use
+              <a href="{@docRoot}google/play-services/auth.html">Google OAuth 2
+              authorization</a> through Google Play Services.
+            </p>
+          </li>
+        </ul>
+      </li>
+    </ul>
+  </li>
+</ul>
+
+<div class="headerLine">
+  <h1 id="test-environment">
+    Test Environment
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  To test your app and assess it against the guidelines in this document, it's
+  recommended that you <a href=
+  "{@docRoot}distribute/essentials/quality/tablets.html#test-environment">set
+  up a test environment</a> that replicates the actual environment in which
+  students and teachers will run your app.
+</p>
+
+<h3>
+  Test conditions
+</h3>
+
+<p>
+  Make sure to test your apps under conditions that simulate those of schools.
+  For example, Google Play for Education lets administrators <a href=
+  "https://support.google.com/a/answer/182442?hl=en">control or disable certain
+  capabilities</a> for students, so it's good to test your app with those
+  capabilities disabled. Below are some conditions to test your apps for, to
+  ensure best results in the Google Play for Education environment:
+</p>
+
+<ul>
+  <li>
+    <p>
+      <em>Android version</em> &mdash; Test the apps on devices running Android
+      4.2. Google Play for Education devices will be running Android 4.2 or
+      higher (API level 17+).
+    </p>
+  </li>
+
+  <li>
+    <p>
+      <em>Proxy server</em> &mdash; Test the apps in a network environment that
+      uses proxies. Many schools use proxies.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      <em>No location services</em> &mdash; Test the apps to make sure they
+      work properly with location services disabled. Many schools will disable
+      location services for student devices.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      <em>No In-app Billing</em> &mdash; Test the apps to make sure they work
+      properly without access to In-app Billing. In-app purchases are blocked
+      on Google Play for Education devices.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      <em>No Bluetooth</em> &mdash; Test the apps to make sure they work
+      properly when Bluetooth is disabled. Many schools will disable Bluetooth
+      on student devices.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      <em>No access to network</em> &mdash; Test the app to make sure it works
+      properly when the device cannot connect to the internet.
+    </p>
+  </li>
+</ul>
+
+<div class="headerLine">
+<h1>Related Resources</h1><hr>
+</div>
+
+<div class="dynamic-grid">
+<h3>FOR DEVELOPERS</h3>
+
+<div class="resource-widget resource-flow-layout col-13"
+    data-query="collection:distribute/essentials/eduessentials/developers"
+    data-sortOrder="-timestamp"
+    data-cardSizes="6x3,6x3,6x3"
+    data-maxResults="6"></div>
+
+<h3>FOR TEACHERS AND EDUCATORS</h3>
+
+<div class="resource-widget resource-flow-layout col-13"
+    data-query="collection:distribute/essentials/eduessentials/educators"
+    data-sortOrder="-timestamp"
+    data-cardSizes="6x3,6x3,6x3"
+    data-maxResults="3"></div>
+</div>
\ No newline at end of file
diff --git a/docs/html/distribute/essentials/index.jd b/docs/html/distribute/essentials/index.jd
new file mode 100644
index 0000000..ca5442a
--- /dev/null
+++ b/docs/html/distribute/essentials/index.jd
@@ -0,0 +1,34 @@
+page.title=Essentials for a Successful App
+meta.tags="landing, quality"
+page.tags="guidelines", "tablet", "quality"
+section.landing=true
+nonavpage=true
+
+@jd:body
+
+<p>
+  A focus on quality should be part of your entire app delivery process: from
+  initial concept through app and UI design, coding and testing and onto a
+  process of monitoring feedback and making improvement after launch.
+</p>
+
+<div class="dynamic-grid">
+<div class="resource-widget resource-flow-layout landing col-16"
+  data-query="collection:distribute/essentials"
+  data-cardSizes="6x6"
+  data-maxResults="6">
+</div>
+
+<h3>Related resources</h3>
+
+<div class="resource-widget resource-flow-layout col-16"
+  data-query="type:blog+tag:quality"
+  data-cardSizes="6x3"
+  data-maxResults="3">
+</div>
+<div class="resource-widget resource-flow-layout col-16"
+  data-query="type:youtube+tag:appquality"
+  data-cardSizes="6x3"
+  data-maxResults="3">
+</div>
+</div>
\ No newline at end of file
diff --git a/docs/html/distribute/essentials/optimizing-your-app.jd b/docs/html/distribute/essentials/optimizing-your-app.jd
new file mode 100644
index 0000000..3fe91b28
--- /dev/null
+++ b/docs/html/distribute/essentials/optimizing-your-app.jd
@@ -0,0 +1,517 @@
+page.title=Optimize Your App
+page.metaDescription=A look at how to get the most visibility and the highest ratings possible for your app or game. Optimizing the quality of your apps is a key strategy.
+page.image=/distribute/images/gp-optimize-card.jpg
+
+@jd:body
+
+<div id="qv-wrapper">           
+  <div id="qv">
+    <h2>Strategies</h2>
+    <ol>
+      <li><a href="#listen-to-your-users">Listen to Your Users</a></li>
+      <li><a href="#measuring-analyzing-responding">Measuring, Analyzing, and Responding to User Behavior</a></li>
+      <li><a href="#improve-stability">Improve Stability and Eliminate Bugs</a></li>
+      <li><a href="#improve-ui">Improve UI Responsiveness</a></li>
+      <li><a href="#improve-usability">Improve Usability</a></li>
+      <li><a href="#professional-appearance">Professional Appearance and Aesthetics</a></li>
+      <li><a href="#deliver-features">Deliver the Right Set of Features</a></li>
+      <li><a href="#integrate">Integrate with the System and Third-Party Apps</a></li>
+      <li><a href="#related-resources">Related Resources</a></li>
+    </ol>
+  </div>
+</div>
+
+<div class="top-right-float">
+  <img src="{@docRoot}images/gp-optimize.png" class="quality-top-image" style=
+  "width:239px;padding-left:1.5em;">
+</div>
+
+<p>
+  With thousands of new apps being published in Google Play every week, it's
+  important to look for ways to get the most visibility and the highest ratings
+  possible. Optimizing the quality of your apps is a key strategy.
+</p>
+
+<p>
+  A higher quality app can translate to higher user ratings, generally better
+  rankings, more downloads, and higher retention (longer install periods).
+  High-quality apps are much more likely to get positive publicity, such as
+  being featured in Google Play or generating social media buzz.
+</p>
+
+<p>
+  The quality of your apps is something you should consider addressing both
+  before and after launch. Gaining users after the launch of a poor quality app
+  can be hard and recovering costly. On the other hand, maintaining the ranking
+  of high-quality apps is made easier if there are continual improvements, a
+  practice that also fuels the impression-install-ranking cycle.
+</p>
+
+<p>
+  On this page you can find advice on a number of ways in which you can drive
+  improvements to your apps’ quality.
+</p>
+
+<div class="headerLine">
+  <h1 id="listen-to-your-users">
+    Listen to Your Users
+  </h1>
+
+  <hr>
+</div>
+
+<div class="figure">
+  <img src="{@docRoot}images/gp-optimizing-chat-bubbles.png">
+</div>
+
+<p>
+  Listening and hearing your users can be one of your best tools for success.
+  Start listening to your users before launching your apps and continue to
+  listen after launch.
+</p>
+
+<h3>
+  <strong>Listening before you launch</strong>
+</h3>
+
+<p>
+  You can listen to your users during the development of your apps. This
+  process can start with focus groups to review app features, continue into
+  user experience workshops, and onto alpha and beta releases. Listening at
+  these stages has two main benefits: <strong>you’ll build apps with features
+  users want</strong> and <strong>any issues they identify will be cheaper and
+  quicker to fix</strong> than they would be once the app is launched fully.
+</p>
+
+<p>
+  If the practicalities of focus groups and user workshops seem excessive in
+  relation to the development of a particular app, drawing on the feedback of
+  colleagues, friends, and family can be much more useful than getting no
+  feedback at all.
+</p>
+
+<p>
+  It's crucial to conduct user testing before releasing your apps to Google
+  Play. If you can only engage with colleagues, friends, and family you’re
+  already making a good start. For more extensive testing consider a public
+  alpha/beta test or creating your own trusted tester program. You can manage
+  app distribution yourself through email or your own website, or you can use
+  <a href=
+  "{@docRoot}distribute/googleplay/developer-console.html#alpha-beta">beta-testing</a>
+  and <a href=
+  "{@docRoot}distribute/googleplay/developer-console.html#staged-rollouts">staged
+  rollouts</a> in conjunction with <a href=
+  "http://www.google.com/+/business/">Google+</a> or <a href=
+  "https://groups.google.com/forum/#!overview">Google Groups</a> to distribute
+  software and gather feedback to a subset of users. <strong>Users on alpha or
+  beta versions cannot leave reviews or ratings</strong>, so there is
+  <strong>no risk to your rating</strong> on Google Play.
+</p>
+
+<p>
+  Unless you have to, don’t restrict the users you involve in these stages in
+  the information they can share through their social networks and blogs -
+  users engaged in these early stages (and listened too) are likely to be great
+  ambassadors for your apps and will help create great social media buzz.
+</p>
+
+<h3>
+  Listening after launch
+</h3>
+
+<p>
+  Once you have launched, the most obvious way to listen to users is by reading
+  and addressing comments on Google Play. Although the comments aren't always
+  productive or constructive, some will provide valuable insight on aspects of
+  your apps. It's important to remember that users have the opportunity to
+  change their ratings and comments as much as they like.
+</p>
+
+<p>
+  There are more interactive ways you can reach users, help them address their
+  concerns, and gather more detailed feedback: by setting up support and
+  discussion forums. There are some great support tools out there that can put
+  you in touch with your users directly, from forums such as <a href=
+  "http://groups.google.com/">Google Groups</a> to comprehensive customer
+  support products and tools like UserVoice. Once you get set up with such a
+  tool, make sure to fill in the support link in your Google Play product
+  details page — users do click through to these.
+</p>
+
+<p>
+  Also don’t forget to use the <a href=
+  "{@docRoot}distribute/googleplay/developer-console.html#alpha-beta">beta-testing</a>
+  and <a href=
+  "{@docRoot}distribute/googleplay/developer-console.html#staged-rollouts">staged
+  rollout</a> features of Google Play with app updates.
+</p>
+
+<div class="headerLine" id="measuring-analyzing-responding">
+  <h1>
+    Measuring, Analyzing, and Responding to User Behavior
+  </h1>
+
+  <hr>
+</div>
+
+<div class="figure">
+  <img src="{@docRoot}images/gp-optimize-analytics.png">
+</div>
+
+<p>
+  One of the best ways to spot issues to resolve is by measuring user behavior.
+  Optimizing your app becomes much easier when you analyze performance before
+  and after you launch. Drop off points, low ratings, and high percent of
+  uninstalls can be indicative that there’s a problem. Measuring and responding
+  to user-related metrics such as download sources, retention rates, and in-app
+  behavior regularly is critical to keeping and bringing back your hard earned
+  user base.
+</p>
+
+<p>
+  You can get data from tools in Google Play or third-parties to analyze user
+  behavior. You can identify details such as:
+</p>
+
+<ul>
+  <li>
+    <p>
+      Where installs are coming from.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      The types of users you are acquiring.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      What is causing user churn and how to reduce it.
+    </p>
+  </li>
+</ul>
+
+<h3>
+  Statistics for analyzing installs and ratings
+</h3>
+
+<p>
+  Once you’ve published your app, Google Play makes it easy to see how it’s
+  doing. The <a href="https://play.google.com/apps/publish/">Developer
+  Console</a> gives you access to a variety of anonymized statistics and custom
+  charts that show you the app's installation performance and ratings.
+</p>
+
+<p>
+  You can view data and charts for active, daily, and total installs per unique
+  devices or users, as well as upgrades and uninstalls. You can also view the
+  app's daily average user rating and its cumulative user rating. To help you
+  analyze the data, you can view install and ratings statistics across a
+  variety of different dimensions such as Android version, device, country, app
+  version, and carrier.
+</p>
+
+<div>
+  <img class="border-img" src="{@docRoot}images/gp-dc-stats-mini.png">
+</div>
+
+<p>
+  You can see your app statistics on timeline charts, for all metrics and
+  dimensions. At a glance, the charts highlight your app’s installation and
+  ratings peaks and longer-term trends, which you can correlate to promotions,
+  app improvements, or other factors. You can even focus in on data inside a
+  dimension by highlighting specific data points (such as individual platform
+  versions or languages) on the timeline.
+</p>
+
+<p>
+  You can download all of your installation data as a CSV file for viewing in
+  the business program of your choice.
+</p>
+
+<h3>
+  Tracking and analyzing Marketing campaigns
+</h3>
+
+<p>
+  While you should consider monitoring user behavior data as a part of your
+  normal activities, it’s particularly important when you’re running any form
+  of marketing campaign, to make sure you’re getting the right users at the
+  lowest cost possible.
+</p>
+
+<p>
+  One way to track your marketing campaigns is to link <a href=
+  "http://android-developers.blogspot.com/2013/10/improved-app-insight-by-linking-google.html">
+  Google Analytics with your Google Play account</a> to analyze activity from
+  source to install.
+</p>
+
+<div style="margin-top:1em;">
+  <img src="{@docRoot}images/gp-optimizing-image-4.jpg" class="border-img">
+</div>
+
+<p>
+  You can also use any of the variety of tools on the market to help track your
+marketing success and improvement ROI if you wish. There are also third parties
+who can help automate, measure, and optimize your mobile marketing.
+</p>
+
+<div class="headerLine">
+  <h1 id="improve-stability">
+    Improve Stability and Eliminate Bugs
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  There are many tools and techniques for testing and profiling your app on
+  different devices and user scenarios.
+</p>
+
+<p>
+  One noteworthy and yet relatively underused tool for catching stability
+  issues such as crashes is the <a href=
+  "{@docRoot}tools/help/monkey.html">UI/Application Exerciser Monkey</a>
+  (Monkey). Monkey will send random UI events to your app's activities,
+  allowing you to trigger user flows that can uncover stability problems.
+</p>
+
+<p>
+  Also, with the Google error-reporting features built into most Android
+  devices, users have a way to report application crashes to you. The error
+  reports show up in aggregate in the Google Play Developer Console. Make sure
+  to read these reports often and act on them appropriately.
+</p>
+
+<p>
+  Last, keep an external bug and feature request tracker and let users know how
+  to find it. This will enable them to engage with the app at a closer level,
+  by following features and bugs that affect them. User frustration with app
+  problems can be effectively managed with diligent issue tracking and
+  communication. Several community support tools offer issue tracking features,
+  and if your project is open source, most popular repository hosting sites
+  offer this as well.
+</p>
+
+<div class="headerLine">
+  <h1 id="improve-ui">
+    Improve UI Responsiveness
+  </h1>
+
+  <hr>
+</div>
+
+<div class="figure">
+  <img src="{@docRoot}images/gp-optimize-speed.png">
+</div>
+
+<p>
+  One sure-fire way to lose your users is to give them a slow, unresponsive UI.
+  Research has shown that <a href=
+  "http://googleresearch.blogspot.com/2009/06/speed-matters.html">speed
+  matters</a>, for any interface, on mobile, web, or desktop. In fact, the
+  importance of speed is amplified on mobile devices since users often need
+  their information on the go and in a hurry.
+</p>
+
+<p>
+  You can improve your apps' UI responsiveness by moving long-running
+  operations off the main thread to worker threads. Android offers built-in
+  debugging facilities such as StrictMode for analyzing your app's performance
+  and activities on the main thread. See more recommendations in <a href=
+  "http://www.youtube.com/watch?v=c4znvD-7VDA">Writing Zippy Android Apps</a>,
+  a developer session from Google I/O 2010.
+</p>
+
+<p>
+  A great way to improve UI performance is to minimize the complexity of your
+  layouts. If you open up <a href=
+  "{@docRoot}tools/help/hierarchy-viewer.html">hierarchyviewer</a> and see that
+  your layouts are more than 5 levels deep, it may be time to simplify your
+  layout. Consider refactoring those deeply nested <a href=
+  "{@docRoot}reference/android/widget/LinearLayout.html">LinearLayouts</a> into
+  <a href="{@docRoot}guide/topics/ui/layout/relative.html">RelativeLayout</a>.
+  The impact of View objects is cumulative — each one costs about 1 to 2 KB of
+  memory, so large view hierarchies can be a recipe for disaster, causing
+  frequent VM garbage collection passes which block the main (UI) thread. You
+  can learn more from the Google I/O session <a href=
+  "http://www.youtube.com/watch?v=wDBM6wVEO70">World of ListView</a>.
+</p>
+
+<p>
+  Lastly, as pointed out in the blog post <a href=
+  "http://android-developers.blogspot.com/2010/10/traceview-war-story.html">Traceview
+  War Story</a>, tools like <a href=
+  "{@docRoot}tools/help/traceview.html">traceview and ddms</a> can be your best
+  friends in improving your app by profiling method calls and monitoring VM
+  memory allocations, respectively.
+</p>
+
+<div class="headerLine">
+  <h1 id="improve-usability">
+    Improve Usability
+  </h1>
+
+  <hr>
+</div>
+
+<div class="sidebox-wrapper" style="float:right;">
+  <div class="sidebox">
+    <p>
+      <strong>Tip:</strong> As you’re designing or evaluating your app's UI,
+      make sure to read and become familiar with the <a href=
+      "{@docRoot}design/index.html">Android Design</a> guidelines. Included are
+      many examples of UI patterns, styles, and building blocks, as well as
+      tools for the design process.
+    </p>
+  </div>
+</div>
+
+<p>
+  In usability and in app design too, you should listen carefully to your
+  users. Ask a handful of real Android device users (friends, family, etc.) to
+  try out your app and observe them as they interact with it. Look for cases
+  where they get confused, are unsure of how to proceed, or are surprised by
+  certain behaviors. Minimize these cases by rethinking some of the
+  interactions in your app. See the <a href=
+  "{@docRoot}design/patterns/index.html">Patterns section</a> for tips to
+  improve your design.
+</p>
+
+<p>
+  In the same vein, two problems that can plague some Android user interfaces
+  are small tap targets and excessively small font sizes. These are generally
+  easy to fix and can make a big impact on usability and user satisfaction. As
+  a general rule, optimize for ease of use and legibility, while minimizing, or
+  at least carefully balancing, information density.
+</p>
+
+<p>
+  Another way to incrementally improve usability, based on real-world data, is
+  to implement <a href=
+  "http://code.google.com/mobile/analytics/docs/">Analytics</a> throughout your
+  app to log the use of particular sections. Consider demoting infrequently
+  used sections to the overflow menu in the <a href=
+  "{@docRoot}design/patterns/actionbar.html">Action bar</a>, or removing them
+  altogether. For often-used sections and UI elements, make sure they're
+  immediately obvious and easily accessible in your app's UI so that users can
+  get to them quickly.
+</p>
+
+<div class="headerLine">
+  <h1 id="professional-appearance">
+    Professional Appearance and Aesthetics
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  There's no substitute for a real user interface designer — ideally one who's
+  well-versed in mobile and Android, and handy with both interaction and visual
+  design. One popular venue to post openings for designers is <a href=
+  "http://jobs.smashingmagazine.com/">jobs.smashingmagazine.com</a>, and
+  leveraging social networks can also surface great talent.
+</p>
+
+<p>
+  If you don't have the luxury of working with a UI designer, there are some
+  ways in which you can improve your app's appearance yourself. You can use
+  Adobe Photoshop, Adobe Fireworks, GIMP, Inkscape or other image editing
+  tools. Mastering the art of the pixel in these apps takes time, but honing
+  this skill can help build polish across your interface designs. Also, master
+  the resources framework by studying the framework UI assets and layouts and
+  reading through the <a href=
+  "{@docRoot}guide/topics/resources/index.html">resources documentation</a>.
+  Techniques such as 9-patches and resource directory qualifiers are somewhat
+  unique to Android, and are crucial in building flexible yet aesthetic UIs.
+</p>
+
+<p>
+  Before you get too far in designing your app and writing the code, make sure
+  to visit the <a href="{@docRoot}design/index.html">Android Design section</a>
+  and learn about the vision, the building blocks, and the tools of designing
+  beautiful and inspiring user interfaces.
+</p>
+
+<div class="headerLine">
+  <h1 id="deliver-features">
+    Deliver the Right Set of Features
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  Having the <em>right</em> set of features in your app is important. It's
+  often easy to fall into the trap of feature-creep, building as much
+  functionality into your app as possible. Providing instant gratification by
+  immediately showing the most important or relevant information is crucial on
+  mobile devices. Providing too much information can be as frustrating (or even
+  more so) than not providing enough of it.
+</p>
+
+<p>
+  Again, listen to your users by collecting and responding to feature requests.
+  Be careful, though, to take feature requests with a grain of salt. Requests
+  can be very useful in aggregate, to get a sense of what kinds of
+  functionality you should be working on, but not every feature request needs
+  to be implemented.
+</p>
+
+<div class="headerLine">
+  <h1 id="integrate">
+    Integrate with the System and Third-Party apps
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  A great way to deliver a delightful user experience is to integrate tightly
+  with the operating system. Features like <a href=
+  "{@docRoot}guide/topics/appwidgets/index.html">Home screen widgets</a>,
+  <a href="{@docRoot}design/patterns/notifications.html">rich
+  notifications</a>, <a href="{@docRoot}guide/topics/search/index.html">global
+  search integration</a>, and <a href=
+  "{@docRoot}reference/android/widget/QuickContactBadge.html">Quick
+  Contacts</a> are fairly low-hanging fruit in this regard.
+</p>
+
+<p>
+  For some app categories, basic features like home screen widgets are
+  expected. Not including them is a sure-fire way to tarnish an otherwise
+  positive user experience. Some apps can achieve even tighter OS integration
+  with Android's contacts, accounts, and sync APIs.
+</p>
+
+<p>
+  Third-party integrations can provide even more user delight and give the user
+  a feeling of device cohesiveness. It's also a really nice way of adding
+  functionality to your app without writing any extra code (by leveraging other
+  apps' functionality). For example, if you're creating a camera app, you can
+  allow users to edit their photos in another app before saving them to their
+  collection, if they have that third-party application installed. More
+  information on this subject is available in the Android Training class
+  <a href="{@docRoot}training/basics/intents/index.html">Interacting with Other
+  Apps</a>.
+</p>
+
+<div class="headerLine">
+<h1 id="related-resources">Related Resources</h1><hr>
+</div>
+<div class="resource-widget resource-flow-layout col-13"
+  data-query="collection:distribute/essentials/optimizing, tag:addia"
+  data-sortOrder="-timestamp"
+  data-cardSizes="6x3"
+  data-maxResults="3"></div>
+<div class="resource-widget resource-flow-layout col-13"
+  data-query="tag:adia"
+  data-sortOrder="-timestamp"
+  data-cardSizes="6x3"
+  data-maxResults="3"></div>
+
diff --git a/docs/html/distribute/essentials/quality/core.jd b/docs/html/distribute/essentials/quality/core.jd
new file mode 100644
index 0000000..558b030
--- /dev/null
+++ b/docs/html/distribute/essentials/quality/core.jd
@@ -0,0 +1,1170 @@
+page.title=Core App Quality
+page.metaDescription=App quality directly influences the long-term success of your app—in terms of installs, user rating and reviews, engagement, and user retention.
+page.image=/distribute/images/core-quality-guidelines.jpg
+@jd:body
+
+<div id="qv-wrapper"><div id="qv">
+<h2>Quality Criteria</h2>
+  <ol>
+    <li><a href="#ux">Design and Interaction</a></li>
+        <li><a href="#fn">Functionality</a></li>
+        <li><a href="#ps">Performance and Stability</a></li>
+        <li><a href="#listing">Google Play</a></li>
+
+  </ol>
+  
+  <h2>Testing</h2>
+  <ol>
+    <li><a href="#test-environment">Setting Up a Test Environment</a></li>
+        <li><a href="#tests">Test Procedures</a></li>
+        </ol>
+
+  <h2>You Should Also Read</h2>
+  <ol>
+    <li><a href="{@docRoot}distribute/essentials/quality/tablets.html">Tablet App Quality</a></li>
+        <li><a href="{@docRoot}distribute/essentials/optimizing-your-app.html">Optimize Your App</a></li>
+  </ol>
+  
+
+</div>
+</div>
+
+<div class="top-right-float">
+  <img src="{@docRoot}images/gp-core-quality.png" style="margin-left: 20px;">
+</div>
+
+<p>
+  Android users expect high-quality apps. App quality directly influences the
+  long-term success of your app—in terms of installs, user rating and reviews,
+  engagement, and user retention.
+</p>
+
+<p>
+  This document helps you assess basic aspects of quality in your app through a
+  compact set of core app quality criteria and associated tests. All Android
+  apps should meet these criteria.
+</p>
+
+<p>
+  Before publishing your apps, test them against these criteria to ensure that
+  they function well on many devices, meets Android standards for navigation
+  and design, and are prepared for promotional opportunities in the Google Play
+  store. Your testing will go well beyond what's described here—the purpose of
+  this document is to specify the essential quality characteristics all apps
+  should display, so that you can cover them in your test plans.
+</p>
+
+<p>
+  If you're creating apps for tablets and or Google Play for Education there
+  are additional quality criteria you should consider, which are defined in the
+  <a href="{@docRoot}distribute/essentials/quality/tablets.html">Tablet App
+  Quality</a> guidelines and <a href=
+  "{@docRoot}distribute/essentials/gpfe-guidelines.html">Education
+  Guidelines</a>.
+</p>
+
+<div class="headerLine clearfloat">
+  <h1 id="ux">
+  Visual Design and User Interaction
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  These criteria ensure that your app provides standard Android visual design
+  and interaction patterns where appropriate, for a consistent and intuitive
+  user experience.
+</p>
+
+<table>
+  <tr>
+    <th style="width:2px;">
+      Area
+    </th>
+    <th style="width:54px;">
+      ID
+    </th>
+    
+
+    <th>
+      Description
+    </th>
+    <th style="width:54px;">
+      Tests
+    </th>
+  </tr>
+  <tr id="UX-B1">
+  <td>Standard design</td>
+  <td>
+    UX-B1
+  </td>
+  <td>
+    <p style="margin-bottom:.5em;">
+    App follows <a href="{@docRoot}design/index.html">Android Design</a>
+    guidelines and uses common <a href=
+    "{@docRoot}design/patterns/index.html">UI patterns and icons</a>:
+    </p>
+
+    <ol style="margin-bottom:.5em;list-style-type:lower-alpha">
+    <li>App does not redefine the expected function of a system icon (such
+    as the Back button).
+    </li>
+
+    <li>App does not replace a system icon with a completely different icon
+    if it triggers the standard UI behavior.
+    </li>
+
+    <li>If the app provides a customized version of a standard system icon,
+    the icon strongly resembles the system icon and triggers the standard
+    system behavior.
+    </li>
+
+    <li>App does not redefine or misuse Android UI patterns, such that
+    icons or behaviors could be misleading or confusing to users.
+    </li>
+    </ol>
+  </td>
+  <td>
+    <a href="#core">CR-all</a>
+  </td>
+  </tr>
+
+  <tr>
+  <td rowspan="3">
+    Navigation
+  </td>
+  <td id="UX-N1">
+    UX-N1
+  </td>
+  <td>
+    <p>
+    App supports standard system <a href=
+    "{@docRoot}design/patterns/navigation.html">Back button navigation</a>
+    and does not make use of any custom, on-screen "Back button" prompts.
+    </p>
+  </td>
+  <td>
+    <a href="#core">CR-3</a>
+  </td>
+  </tr>
+
+  <tr>
+  <td id="UX-N2">
+    UX-N2
+  </td>
+  <td>
+    <p>
+    All dialogs are dismissable using the Back button.
+    </p>
+  </td>
+  <td>
+    <a href="#core">CR-3</a>
+  </td>
+  </tr>
+
+  <tr id="UX-N3">
+  <td>
+    UX-N3
+  </td>
+  <td>
+    Pressing the Home button at any point navigates to the Home screen of the
+    device.
+  </td>
+  <td>
+    <a href="#core">CR-1</a>
+  </td>
+  </tr>
+
+  <tr id="UX-S1">
+  <td rowspan="2">
+    Notifications
+  </td>
+  <td>
+    UX-S1
+  </td>
+  <td>
+    <p style="margin-bottom:.5em;">
+    Notifications follow Android Design <a href=
+    "{@docRoot}design/patterns/notifications.html">guidelines</a>. In
+    particular:
+    </p>
+
+    <ol style="margin-bottom:.5em;list-style-type:lower-alpha">
+    <li>Multiple notifications are stacked into a single notification
+    object, where possible.
+    </li>
+
+    <li>Notifications are persistent only if related to ongoing events
+    (such as music playback or a phone call).
+    </li>
+
+    <li>Notifications do not contain advertising or content unrelated to
+    the core function of the app, unless the user has opted in.
+    </li>
+    </ol>
+  </td>
+  <td>
+    <a href="#core">CR-11</a>
+  </td>
+  </tr>
+
+  <tr id="UX-S2">
+  <td>
+    UX-S2
+  </td>
+  <td>
+    <p style="margin-bottom:.5em;">
+    App uses notifications only to:
+    </p>
+
+    <ol style="margin-bottom:.5em;list-style-type:lower-alpha">
+    <li>Indicate a change in context relating to the user personally (such
+    as an incoming message), or
+    </li>
+
+    <li>Expose information/controls relating to an ongoing event (such as
+    music playback or a phone call).
+    </li>
+    </ol>
+  </td>
+  <td>
+    <a href="#core">CR-11</a>
+  </td>
+  </tr>
+</table>
+
+<h3>
+  Related Resources
+</h3>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/essentials/corequalityguidelines/visualdesign"
+data-sortorder="-timestamp" data-cardsizes="9x3,9x3,6x3,6x3,6x3"
+data-maxresults="6">
+</div>
+
+<div class="headerLine clearfloat">
+  <h1 id="fn">
+  Functionality
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  These criteria ensure that your app provides expected functional behavior,
+  with the appropriate level of permissions.
+</p>
+
+<table>
+  <tr>
+  <th style="width:2px;">
+    Area
+  </th>
+  <th style="width:54px;">
+    ID
+  </th>
+  <th>
+    Description
+  </th>
+  <th style="width:54px;">
+    Tests
+  </th>
+  </tr>
+
+  <tr id="FN-P1">
+  <td rowspan="2">
+    Permissions
+  </td>
+  <td>
+    FN-P1
+  </td>
+  <td>
+    App requests only the <em>absolute minimum</em> permissions that it needs
+    to support core functionality.
+  </td>
+  <td rowspan="2">
+    <a href="#core">CR-11</a>
+  </td>
+  </tr>
+
+  <tr id="FN-P2">
+  <td>
+    FN-P2
+  </td>
+  <td>
+    <p style="margin-bottom:.5em;">
+    App does not request permissions to access sensitive data (such as
+    Contacts or the System Log) or services that can cost the user money
+    (such as the Dialer or SMS), unless related to a core capability of the
+    app.
+    </p>
+  </td>
+  </tr>
+
+  <tr id="FN-L1">
+  <td>
+    Install location
+  </td>
+  <td>
+    FN-L1
+  </td>
+  <td>
+    <p style="margin-bottom:.5em;">
+    App functions normally when installed on SD card (if supported by app).
+    </p>
+
+    <p style="margin-bottom:.25em;">
+    Supporting installation to SD card is recommended for most large apps
+    (10MB+). See the <a href=
+    "{@docRoot}guide/topics/data/install-location.html">App Install
+    Location</a> developer guide for information about which types of apps
+    should support installation to SD card.
+    </p>
+  </td>
+  <td>
+    <a href="#SD-1">SD-1</a>
+  </td>
+  </tr>
+
+  <tr id="FN-A1">
+  <td rowspan="4">
+    Audio
+  </td>
+  <td>
+    FN-A1
+  </td>
+  <td>
+    Audio does not play when the screen is off, unless this is a core feature
+    (for example, the app is a music player).
+  </td>
+  <td>
+    <a href="#core">CR-7</a>
+  </td>
+  </tr>
+
+  <tr id="FN-A2">
+  <td>
+    FN-A2
+  </td>
+  <td>
+    Audio does not <a href=
+    "http://android-developers.blogspot.com/2011/11/making-android-games-that-play-nice.html">
+    play behind the lock screen</a>, unless this is a core feature.
+  </td>
+  <td>
+    <a href="#core">CR-8</a>
+  </td>
+  </tr>
+
+  <tr id="FN-A3">
+  <td>
+    FN-A3
+  </td>
+  <td>
+    Audio does not play on the home screen or over another app, unless this
+    is a core feature.
+  </td>
+  <td>
+    <a href="#core">CR-1,<br>
+    CR-2</a>
+  </td>
+  </tr>
+
+  <tr id="FN-A4">
+  <td>
+    FN-A4
+  </td>
+  <td>
+    Audio resumes when the app returns to the foreground, or indicates to the
+    user that playback is in a paused state.
+  </td>
+  <td>
+    <a href="#core">CR-1, CR-8</a>
+  </td>
+  </tr>
+
+  <tr id="FN-U1">
+  <td rowspan="3">
+    UI and Graphics
+  </td>
+  <td>
+    FN-U1
+  </td>
+  <td>
+    <p style="margin-bottom:.5em;">
+    App supports both landscape and portrait orientations (if possible).
+    </p>
+
+    <p style="margin-bottom:.25em;">
+    Orientations expose largely the same features and actions and preserve
+    functional parity. Minor changes in content or views are acceptable.
+    </p>
+  </td>
+  <td>
+    <a href="#core">CR-5</a>
+  </td>
+  </tr>
+
+  <tr id="FN-U2">
+  <td>
+    FN-U2
+  </td>
+  <td>
+    <p style="margin-bottom:.5em;">
+    App uses the whole screen in both orientations and does not letterbox
+    to account for orientation changes.
+    </p>
+
+    <p style="margin-bottom:.25em;">
+    Minor letterboxing to compensate for small variations in screen
+    geometry is acceptable.
+    </p>
+  </td>
+  <td>
+    <a href="#core">CR-5</a>
+  </td>
+  </tr>
+
+  <tr id="FN-U3">
+  <td>
+    FN-U3
+  </td>
+  <td>
+    <p style="margin-bottom:.5em;">
+    App correctly handles rapid transitions between display orientations
+    without rendering problems.
+    </p>
+  </td>
+  <td>
+    <a href="#core">CR-5</a>
+  </td>
+  </tr>
+
+  <tr id="FN-S1">
+  <td rowspan="2">
+    User/app state
+  </td>
+  <td>
+    FN-S1
+  </td>
+  <td>
+    <p style="margin-bottom:.5em;">
+    App should not leave any services running when the app is in the
+    background, unless related to a core capability of the app.
+    </p>
+
+    <p style="margin-bottom:.25em;">
+    For example, the app should not leave services running to maintain a
+    network connection for notifications, to maintain a Bluetooth
+    connection, or to keep the GPS powered-on.
+    </p>
+  </td>
+  <td>
+    <a href="#core">CR-6</a>
+  </td>
+  </tr>
+
+  <tr id="FN-S2">
+  <td>
+    FN-S2
+  </td>
+  <td>
+    <p style="margin-bottom:.5em;">
+    App correctly preserves and restores user or app state.
+    </p>
+
+    <p style="margin-bottom:.25em;">
+    App preserves user or app state when leaving the foreground and
+    prevents accidental data loss due to back-navigation and other state
+    changes. When returning to the foreground, the app must restore the
+    preserved state and any significant stateful transaction that was
+    pending, such as changes to editable fields, game progress, menus,
+    videos, and other sections of the app or game.
+    </p>
+
+    <ol style="margin-bottom:.25em;list-style-type:lower-alpha">
+    <li>When the app is resumed from the Recents app switcher, the app
+    returns the user to the exact state in which it was last used.
+    </li>
+
+    <li>When the app is resumed after the device wakes from sleep (locked)
+    state, the app returns the user to the exact state in which it was last
+    used.
+    </li>
+
+    <li>When the app is relaunched from Home or All Apps, the app restores
+    the app state as closely as possible to the previous state.
+    </li>
+
+    <li>On Back keypresses, the app gives the user the option of saving any
+    app or user state that would otherwise be lost on back-navigation.
+    </li>
+    </ol>
+  </td>
+  <td>
+    <a href="#core">CR-1, CR-3, CR-5</a>
+  </td>
+  </tr>
+</table>
+
+<h3>
+  Related Resources
+</h3>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/essentials/corequalityguidelines/functionality"
+data-sortorder="-timestamp" data-cardsizes="6x3" data-maxresults="6">
+</div>
+
+<div class="headerLine clearfloat">
+  <h1 id="ps">
+  Performance and Stability
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  These criteria ensure that apps provide the performance, stability, and
+  responsiveness expected by users.
+</p>
+
+<table>
+  <tr>
+  <th style="width:2px;">
+    Area
+  </th>
+  <th style="width:54px;">
+    ID
+  </th>
+  <th>
+    Description
+  </th>
+  <th style="width:54px;">
+    Tests
+  </th>
+  </tr>
+
+  <tr id="PS-S1">
+  <td>
+    Stability
+  </td>
+  <td>
+    PS-S1
+  </td>
+  <td>
+    App does not crash, force close, freeze, or otherwise function abnormally
+    on any targeted device.
+  </td>
+  <td>
+    <a href="#core">CR-all</a>, <a href="#SD-1">SD-1</a>, <a href=
+    "#HA-1">HA-1</a>
+  </td>
+  </tr>
+
+  <tr id="PS-P1">
+  <td rowspan="2">
+    Performance
+  </td>
+  <td>
+    PS-P1
+  </td>
+  <td>
+    App loads quickly or provides onscreen feedback to the user (a progress
+    indicator or similar cue) if the app takes longer than two seconds to
+    load.
+  </td>
+  <td>
+    <a href="#core">CR-all</a>, <a href="#SD-1">SD-1</a>
+  </td>
+  </tr>
+
+  <tr id="PS-P2">
+  <td>
+    PS-P2
+  </td>
+  <td>
+    With StrictMode enabled (see <a href="#strictmode">StrictMode
+    Testing</a>, below), no red flashes (performance warnings from
+    StrictMode) are visible when exercising the app, including during game
+    play, animations and UI transitions, and any other part of the app.
+  </td>
+  <td>
+    <a href="#PM-1">PM-1</a>
+  </td>
+  </tr>
+
+  <tr id="PS-M1">
+  <td>
+    Media
+  </td>
+  <td>
+    PS-M1
+  </td>
+  <td>
+    Music and video playback is smooth, without crackle, stutter, or other
+    artifacts, during normal app usage and load.
+  </td>
+  <td>
+    <a href="#core">CR-all</a>, <a href="#SD-1">SD-1</a>, <a href=
+    "#HA-1">HA-1</a>
+  </td>
+  </tr>
+
+  <tr id="PS-V1">
+  <td rowspan="2">
+    Visual quality
+  </td>
+  <td>
+    PS-V1
+  </td>
+  <td>
+    <p style="margin-bottom:.5em;">
+    App displays graphics, text, images, and other UI elements without
+    noticeable distortion, blurring, or pixelation.
+    </p>
+
+    <ol style="margin-bottom:.5em;list-style-type:lower-alpha">
+    <li>App provides high-quality graphics for all targeted screen sizes
+    and form factors, including for <a href=
+    "{@docRoot}distribute/essentials/quality/tablet.html">larger-screen
+    devices such as tablets</a>.
+    </li>
+
+    <li>No aliasing at the edges of menus, buttons, and other UI elements
+    is visible.
+    </li>
+    </ol>
+  </td>
+  <td rowspan="2">
+    <a href="#core">CR-all</a>
+  </td>
+  </tr>
+
+  <tr id="PS-V2">
+  <td>
+    PS-V2
+  </td>
+  <td>
+    <p style="margin-bottom:.5em;">
+    App displays text and text blocks in an acceptable manner.
+    </p>
+
+    <ol style="margin-bottom:.5em;list-style-type:lower-alpha">
+    <li>Composition is acceptable in all supported form factors, including
+    for larger-screen devices such as tablets.
+    </li>
+
+    <li>No cut-off letters or words are visible.
+    </li>
+
+    <li>No improper word wraps within buttons or icons are visible.
+    </li>
+
+    <li>Sufficient spacing between text and surrounding elements.
+    </li>
+    </ol>
+  </td>
+  </tr>
+</table>
+
+<h3>
+  Related Resources
+</h3>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/essentials/core/performance" data-sortorder="-timestamp"
+data-cardsizes="6x3" data-maxresults="6">
+</div>
+
+<div class="headerLine clearfloat">
+  <h1 id="listing">
+  Google Play
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  These criteria ensure that your apps are ready to publish on Google Play.
+</p>
+
+<table>
+  <tr>
+  <th style="width:2px;">
+    Area
+  </th>
+  <th style="width:54px;">
+    ID
+  </th>
+  <th>
+    Description
+  </th>
+  <th style="width:54px;">
+    Tests
+  </th>
+  </tr>
+
+  <tr id="GP-P1">
+  <td rowspan="2">
+    Policies
+  </td>
+  <td>
+    GP-P1
+  </td>
+  <td>
+    App strictly adheres to the terms of the <a href=
+    "http://play.google.com/about/developer-content-policy.html">Google Play
+    Developer Content Policy</a> and does not offer inappropriate content,
+    does not use intellectual property or brand of others, and so on.
+  </td>
+  <td>
+    <a href="#gp">GP-all</a>
+  </td>
+  </tr>
+
+  <tr id="GP-P2">
+  <td>
+    GP-P2
+  </td>
+  <td>
+    <p style="margin-bottom:.5em;">
+    App maturity level is set appropriately, based on the <a href=
+    "http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=188189">
+    Content Rating Guidelines</a>.
+    </p>
+
+    <p style="margin-bottom:.25em;">
+    Especially, note that apps that request permission to use the device
+    location cannot be given the maturity level "Everyone".
+    </p>
+  </td>
+  <td>
+    <a href="#gp">GP-1</a>
+  </td>
+  </tr>
+
+  <tr id="GP-D1">
+  <td rowspan="3">
+    App&nbsp;Details Page
+  </td>
+  <td>
+    GP-D1
+  </td>
+  <td>
+    <p style="margin-bottom:.5em;">
+    App feature graphic follows the guidelines outlined in this <a href=
+    "http://android-developers.blogspot.com/2011/10/android-market-featured-image.html">
+    blog post</a>. Make sure that:
+    </p>
+
+    <ol style="margin-bottom:.5em;list-style-type:lower-alpha">
+    <li>The app listing includes a high-quality feature graphic.
+    </li>
+
+    <li>The feature graphic does not contain device images, screenshots, or
+    small text that will be illegible when scaled down and displayed on the
+    smallest screen size that your app is targeting.
+    </li>
+
+    <li>The feature graphic does not resemble an advertisement.
+    </li>
+    </ol>
+  </td>
+  <td>
+    <a href="#gp">GP-1, GP-2</a>
+  </td>
+  </tr>
+
+  <tr id="GP-D2">
+  <td>
+    GP-D2
+  </td>
+  <td>
+    App screenshots and videos do not show or reference non-Android devices.
+  </td>
+  <td rowspan="2">
+    <a href="#gp">GP-1</a>
+  </td>
+  </tr>
+
+  <tr id="GP-D3">
+  <td>
+    GP-D3
+  </td>
+  <td>
+    App screenshots or videos do not represent the content and experience of
+    your app in a misleading way.
+  </td>
+  </tr>
+
+  <tr id="GP-X1">
+  <td>
+    User Support
+  </td>
+  <td>
+    GP-X1
+  </td>
+  <td>
+    Common user-reported bugs in the Reviews tab of the Google Play page are
+    addressed if they are reproducible and occur on many different devices.
+    If a bug occurs on only a few devices, you should still address it if
+    those devices are particularly popular or new.
+  </td>
+  <td>
+    <a href="#gp">GP-1</a>
+  </td>
+  </tr>
+</table>
+
+<h3>
+  Related Resources
+</h3>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/essentials/core/play" data-sortorder="-timestamp"
+data-cardsizes="6x3,6x3,6x3,6x3,6x3,6x3" data-maxresults="6">
+</div>
+
+<div class="headerLine clearfloat">
+  <h1 id="test-environment">
+  Setting Up a Test Environment
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  To assess the quality of your app, you need to set up a suitable hardware or
+  emulator environment for testing.
+</p>
+
+<p>
+  The ideal test environment would include a small number of actual hardware
+  devices that represent key form factors and hardware/software combinations
+  currently available to consumers. It's not necessary to test on
+  <em>every</em> device that's on the market &mdash; rather, you should focus
+  on a small number of representative devices, even using one or two devices
+  per form factor.
+</p>
+
+<p>
+  If you are not able to obtain actual hardware devices for testing, you should
+  <a href="{@docRoot}tools/devices/index.html">set up emulated devices
+  (AVDs)</a> to represent the most common form factors and hardware/software
+  combinations.
+</p>
+
+<p>
+  To go beyond basic testing, you can add more devices, more form factors, or
+  new hardware/software combinations to your test environment. You can also
+  increase the number or complexity of tests and quality criteria.
+</p>
+
+<div class="headerLine clearfloat">
+  <h1 id="tests">
+  Test Procedures
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  These test procedures help you discover various types of quality issues in
+  your app. You can combine the tests or integrate groups of tests together in
+  your own test plans. See the sections above for references that associate
+  specific criteria with specific tests.
+</p>
+
+<table>
+  <tr>
+  <th style="width:2px;">
+    Type
+  </th>
+  <th style="width:54px;">
+    Test
+  </th>
+  <th>
+    Description
+  </th>
+  </tr>
+
+  <tr>
+  <td rowspan="12" id="core">
+    Core Suite
+  </td>
+  <td>
+    CR-0
+  </td>
+  <td>
+    <p style="margin-bottom:.5em;">
+    Navigate to all parts of the app &mdash; all screens, dialogs,
+    settings, and all user flows.
+    </p>
+
+    <ol style="margin-bottom:.5em;list-style-type:lower-alpha">
+    <li>If the application allows for editing or content creation, game
+    play, or media playback, make sure to enter those flows to create or
+    modify content.
+    </li>
+
+    <li>While exercising the app, introduce transient changes in network
+    connectivity, battery function, GPS or location availability, system
+    load, and so on.
+    </li>
+    </ol>
+  </td>
+  </tr>
+
+  <tr id="tg2">
+  <td id="core2">
+    CR-1
+  </td>
+  <td>
+    From each app screen, press the device's Home key, then re-launch the app
+    from the All Apps screen.
+  </td>
+  </tr>
+
+  <tr id="CR-2">
+  <td>
+    CR-2
+  </td>
+  <td>
+    From each app screen, switch to another running app and then return to
+    the app under test using the Recents app switcher.
+  </td>
+  </tr>
+
+  <tr id="CR-3">
+  <td>
+    CR-3
+  </td>
+  <td>
+    From each app screen (and dialogs), press the Back button.
+  </td>
+  </tr>
+
+  <tr id="CR-5">
+  <td>
+    CR-5
+  </td>
+  <td>
+    From each app screen, rotate the device between landscape and portrait
+    orientation at least three times.
+  </td>
+  </tr>
+
+  <tr id="CR-6">
+  <td>
+    CR-6
+  </td>
+  <td>
+    Switch to another app to send the test app into the background. Go to
+    Settings and check whether the test app has any services running while in
+    the background. In Android 4.0 and higher, go to the Apps screen and find
+    the app in the "Running" tab. In earlier versions, use "Manage
+    Applications" to check for running services.
+  </td>
+  </tr>
+
+  <tr id="CR-7">
+  <td>
+    CR-7
+  </td>
+  <td>
+    Press the power button to put the device to sleep, then press the power
+    button again to awaken the screen.
+  </td>
+  </tr>
+
+  <tr id="CR-8">
+  <td>
+    CR-8
+  </td>
+  <td>
+    Set the device to lock when the power button is pressed. Press the power
+    button to put the device to sleep, then press the power button again to
+    awaken the screen, then unlock the device.
+  </td>
+  </tr>
+
+  <tr id="CR-9">
+  <!-- Hardware features -->
+
+  <td>
+    CR-9
+  </td>
+  <td>
+    For devices that have slide-out keyboards, slide the keyboard in and out
+    at least once. For devices that have keyboard docks, attach the device to
+    the keyboard dock.
+  </td>
+  </tr>
+
+  <tr id="CR-10">
+  <td>
+    CR-10
+  </td>
+  <td>
+    For devices that have an external display port, plug-in the external
+    display.
+  </td>
+  </tr>
+
+  <tr id="CR-11">
+  <td>
+    CR-11
+  </td>
+  <td>
+    Trigger and observe in the notications drawer all types of notifications
+    that the app can display. Expand notifications where applicable (Android
+    4.1 and higher), and tap all actions offered.
+  </td>
+  </tr>
+
+  <tr id="CR-12">
+  <td>
+    CR-12
+  </td>
+  <td>
+    Examine the permissions requested by the app by going to Settings &gt;
+    App Info.
+  </td>
+  </tr>
+
+  <tr id="tg3">
+  <td>
+    Install on SD Card
+  </td>
+  <td>
+    SD-1
+  </td>
+  <td>
+    <p style="margin-bottom:.5em;">
+    Repeat <em>Core Suite</em> with app installed to <a href=
+    "{@docRoot}guide/topics/data/install-location.html">device SD card</a>
+    (if supported by app).
+    </p>
+
+    <p style="margin-bottom:.25em;">
+    To move the app to SD card, you can use Settings &gt; App Info &gt;
+    Move to SD Card.
+    </p>
+  </td>
+  </tr>
+
+  <tr id="tg32">
+  <td>
+    Hardware acceleration
+  </td>
+  <td>
+    HA-1
+  </td>
+  <td>
+    <p style="margin-bottom:.5em;">
+    Repeat <em>Core Suite</em> with hardware acceleration enabled.
+    </p>
+
+    <p style="margin-bottom:.25em;">
+    To force-enable hardware acceleration (where supported by device), add
+    <code>hardware-accelerated="true"</code> to the
+    <code>&lt;application&gt;</code> in the app manifest and recompile.
+    </p>
+  </td>
+  </tr>
+
+  <tr id="tg33">
+  <td>
+    Performance Monitoring
+  </td>
+  <td>
+    PM-1
+  </td>
+  <td>
+    <p style="margin-bottom:.5em;">
+    Repeat <em>Core Suite</em> with StrictMode profiling enabled <a href=
+    "#strictmode">as described below</a>.
+    </p>
+
+    <p style="margin-bottom:.25em;">
+    Pay close attention to garbage collection and its impact on the user
+    experience.
+    </p>
+  </td>
+  </tr>
+
+  <tr id="gp">
+  <td rowspan="3">
+    Google Play
+  </td>
+  <td>
+    GP-1
+  </td>
+  <td>
+    Sign into the <a href="https://play.google.com/apps/publish/">Developer
+    Console</a> to review your developer profile, app description,
+    screenshots, feature graphic, maturity settings, and user feedback.
+  </td>
+  </tr>
+
+  <tr id="GP-2">
+  <td>
+    GP-2
+  </td>
+  <td>
+    Download your feature graphic and screenshots and scale them down to
+    match the display sizes on the devices and form factors you are
+    targeting.
+  </td>
+  </tr>
+
+  <tr id="GP-3">
+  <td>
+    GP-3
+  </td>
+  <td>
+    Review all graphical assets, media, text, code libraries, and other
+    content packaged in the app or expansion file download.
+  </td>
+  </tr>
+
+  <tr id="GP-4">
+  <td>
+    Payments
+  </td>
+  <td>
+    GP-4
+  </td>
+  <td>
+    Navigate to all screens of your app and enter all in-app purchase flows.
+  </td>
+  </tr>
+</table>
+
+<h3 id="strictmode">
+  Testing with StrictMode
+</h3>
+
+<p>
+  For performance testing, we recommend enabling {@link android.os.StrictMode}
+  in your app and using it to catch operations on the main thread and other
+  threads that could affect performance, network accesses, file reads/writes,
+  and so on.
+</p>
+
+<p>
+  You can set up a monitoring policy per thread using {@link
+  android.os.StrictMode.ThreadPolicy.Builder} and enable all supported
+  monitoring in the <code>ThreadPolicy</code> using {@link
+  android.os.StrictMode.ThreadPolicy.Builder#detectAll()}.
+</p>
+
+<p>
+  Make sure to enable <strong>visual notification</strong> of policy violations
+  for the <code>ThreadPolicy</code> using {@link
+  android.os.StrictMode.ThreadPolicy.Builder#penaltyFlashScreen()
+  penaltyFlashScreen()}.
+</p>
diff --git a/docs/html/distribute/essentials/quality/tablets.jd b/docs/html/distribute/essentials/quality/tablets.jd
new file mode 100644
index 0000000..7dfab48
--- /dev/null
+++ b/docs/html/distribute/essentials/quality/tablets.jd
@@ -0,0 +1,867 @@
+page.title=Tablet App Quality
+page.metaDescription=Tablets are a fast-growing part of the Android installed base that offers new opportunities for your apps.
+page.image=/distribute/images/tablet-guidelines-color.jpg
+Xnonavpage=true
+
+@jd:body
+<div id="qv-wrapper"><div id="qv">
+<h2>Checklist</h2>
+<ol>
+<li><a href="#core-app-quality">1. Test for Basic Tablet App Quality</a></li>
+<li><a href="#optimize-layouts">2. Optimize Layouts</a></li>
+<li><a href="#use-extra-space">3. Use Extra Screen Area</a></li>
+<li><a href="#use-tablet-icons">4. Use Assets Designed for Tablets</a></li>
+<li><a href="#adjust-font-sizes">5. Adjust Fonts and Touch Targets</a></li>
+<li><a href="#adjust-widgets">6. Adjust Homescreen Widgets</a></li>
+<li><a href="#offer-full-feature-set">7. Offer Full Feature Set</a></li>
+<li><a href="#android-versions">8. Target Android Versions Properly</a></li>
+<li><a href="#hardware-requirements">9. Declare Dependencies Properly</a></li>
+<li><a href="#support-screens">10. Declare Support for Tablet Screens</a></li>
+<li><a href="#google-play">11. Showcase Your Tablet UI</a></li>
+<li><a href="#google-play-best-practices">12. Follow Best Practices for Publishing in Google Play</a></li>
+
+</ol>
+<h2>Testing</h2>
+<ol>
+<li><a href="#test-environment">Setting Up a Test Environment</a></li>
+</ol>
+</div></div>
+
+<div class="todp-right-float" style="padding-right:0;margin-bottom:1em;">
+  <img src="{@docRoot}distribute/images/tablet-guidelines-color.jpg" style="width:480px;">
+</div>
+
+<p>
+  Tablets are a growing part of the Android installed base and offer new
+  opportunities for <a href="{@docRoot}distribute/stories/tablets.html">user
+  engagement and monetization</a>. The guidelines in this document will help
+  you meet the expectations of tablet users through compelling features and an
+  intuitive, well-designed UI.
+</p>
+
+<p>
+  Although the guidelines are numbered, you can approach them in any order. You
+  should address each guideline’s recommendations to the extent that they’re
+  appropriate for your app, but &mdash; in the interest of delivering the best
+  product to your customers &mdash; follow them to the greatest extent
+  possible.
+</p>
+
+<p>
+  Through the document you'll find links to resources that can
+  help you address each recommendation included.
+</p>
+
+<div class="headerLine"><h1 id="core-app-quality">1. Test for Basic Tablet App Quality</h1><hr></div>
+
+<p>The first step in delivering a great tablet app experience is making sure
+that it meets the <em>core app quality criteria</em> for all of the devices
+and form factors that the app is targeting. For complete information, see the <a
+href="{@docRoot}distribute/essentials/quality/core.html">Core App Quality Guidelines</a>. 
+</p>
+
+<p>
+Before publishing, also ensure that your app passes the basic technical checks and launch criteria, such as:
+</p>
+
+<ul>
+  <li><a href="#android-versions">Targets appropriate Android versions</a></li>
+  <li><a href="#hardware-requirements">Specifies any hardware dependencies properly</a></li>
+  <li><a href="#support-screens">Declares support for appropriate screens</a></li>
+  <li><a href="#use-extra-space">Uses all of the available screen space</a></li>
+  <li><a href="#google-play">Screenshots are uploaded to Google Play</a></li>
+</ul>
+
+<p>If your app is already uploaded to the Google Play Developer Console, you
+  can see how it is doing against these checks  
+  by visiting the <a href="#google-play-optimization-tips">Optimization
+  Tips page</a>.</p>
+
+
+<div class="headerLine clearfloat">
+<h1 id="optimize-layouts">2. Optimize Layouts for Larger Screens</h1><hr></div>
+
+<p>
+  Android makes it easy to develop an app that runs well on a wide range of
+  device screen sizes and form factors. This broad compatibility works in your
+  favor, since it helps you design a single app that you can distribute widely
+  to all of your targeted devices. However, to give your users the best
+  possible experience on each screen configuration &mdash; in particular on
+  tablets &mdash; you need to optimize your layouts and other UI components for
+  each targeted screen configuration. On tablets, optimizing your UI lets you
+  take full advantage of the additional screen available, such as to offer new
+  features, present new content, or enhance the experience in other ways to
+  deepen user engagement.
+</p>
+
+<p>
+  If you developed your app for handsets and now want to distribute it to
+  tablets, you can start by making minor adjustments to your layouts, fonts,
+  and spacing. In some cases &mdash; such as for 7-inch tablets or for a game
+  with large canvas &mdash; these adjustments may be all you need to make your
+  app look great. In other cases, such as for larger tablets, you can redesign
+  parts of your UI to replace "stretched UI" with an efficient multipane UI,
+  easier navigation, and additional content.
+</p>
+
+
+<div style="width:500px;margin:1.5em;margin-top:-16px;">
+<img src="{@docRoot}images/training/app-navigation-multiple-sizes-multipane-bad.png"
+style="padding:4px;margin-bottom:0em;">
+<p class="img-caption"><span
+style="font-weight:500;">Get rid of "stretched" UI</span>: On tablets, single-pane
+layouts lead to awkward whitespace and excessive line lengths. Use padding to
+reduce the width of UI elements and consider using multi-pane layouts.</p>
+</div>
+
+<p>Here are some suggestions:</p>
+
+
+<ul>
+  <li>Provide custom layouts as needed for <code>large</code> and
+  <code>xlarge</code> screens. You can also provide layouts that are loaded
+  based on the screen's <a href=
+  "{@docRoot}guide/practices/screens_support.html#NewQualifiers">shortest
+  dimension</a> or the <a href=
+  "{@docRoot}guide/practices/screens_support.html#NewQualifiers">minimum
+  available width and height</a>.
+  </li>
+
+  <li>At a minimum, customize dimensions such as font sizes, margins, spacing
+  for larger screens, to improve use of space and content legibility.
+  </li>
+
+  <li>Adjust positioning of UI controls so that they are easily accessible to
+  users when holding a tablet, such as toward the sides when in landscape
+  orientation.
+  </li>
+
+  <li>Padding of UI elements should normally be larger on tablets than on
+  handsets. A <a href="{@docRoot}design/style/metrics-grids.html#48dp-rhythm">
+    48dp rhythm</a> (and a 16dp grid) is recommended.
+  </li>
+
+  <li>Adequately pad text content so that it is not aligned directly along
+  screen edges. Use a minimum <code>16dp</code> padding around content near
+  screen edges.
+  </li>
+</ul>
+
+<p>In particular, make sure that your layouts do not appear "stretched"
+across the screen:</p>
+
+<ul>
+<li>Lines of text should not be excessively long &mdash; optimize for a maximum
+100 characters per line, with best results between 50 and 75.</li>
+<li>ListViews and menus should not use the full screen width.</li>
+<li>Use padding to manage the widths of onscreen elements or switch to a
+multi-pane UI for tablets (see next section).</li>
+</ul>
+
+<h3>Related resources</h3>
+
+<div class="resource-widget resource-flow-layout col-13"
+  data-query="collection:distribute/essentials/tabletguidelines/optimize"
+  data-sortOrder="-timestamp"
+  data-cardSizes="6x3"
+  data-maxResults="6"></div>
+
+
+<div class="headerLine clearfloat"><h1 id="use-extra-space">3. Take Advantage of Extra Screen Area</h1><hr></div>
+
+<div style="width:340px;float:right;margin:1.5em;margin-bottom:0;margin-top:0;">
+<img src="{@docRoot}images/training/app-navigation-multiple-sizes-multipane-good.png"
+style="padding:4px;margin-bottom:0em;">
+<p class="img-caption"><span
+style="font-weight:500;">Multi-pane layouts</span> result in a better visual
+balance on tablet screens, while offering more utility and legibility.</p>
+</div>
+
+<p>Tablet screens provide significantly more screen real estate to your app,
+especially when in landscape orientation. In particular, 10-inch tablets offer a
+greatly expanded  area, but even 7-inch tablets give you more space for
+displaying content and engaging users. </p>
+
+<p>As you consider the UI of your app when running on tablets, make sure that it
+is taking full advantage of extra screen area available on tablets. Here are
+some suggestions:</p>
+
+<ul>
+<li>Look for opportunities to include additional content or use an alternative
+treatment of existing content.</li>
+<li>Use <a href="{@docRoot}design/patterns/multi-pane-layouts.html">multi-pane
+layouts</a> on tablet screens to combine single views into a compound view. This
+lets you use the additional screen area more efficiently and makes it easier for
+users to navigate your app. </li>
+<li>Plan how you want the panels of your compound views to reorganize when
+screen orientation changes.</li>
+
+<div style="width:490px;margin:1.5em auto 1.5em 0;">
+<div style="">
+<img src="{@docRoot}images/ui-ex-single-panes.png"
+style="width:490px;padding:4px;margin-bottom:0em;" align="middle">
+<img src="{@docRoot}images/ui-ex-multi-pane.png" style="width:490px;padding:4px;margin-bottom:0em;">
+<p class="image-caption" style="padding:.5em"><span
+style="font-weight:500;">Compound views</span> combine several single views from a
+handset UI <em>(above)</em> into a richer, more efficient UI for tablets
+<em>(below)</em>. </p>
+</div>
+</div>
+
+<li>While a single screen is implemented as an {@link android.app.Activity}
+subclass, consider implementing individual content panels as {@link
+android.app.Fragment} subclasses. This lets you
+maximize code reuse across different form factors and across screens that
+share content.</li>
+<li>Decide on which screen sizes you'll use a multi-pane UI, then provide the
+different layouts in the appropriate screen size buckets (such as
+<code>large</code>/<code>xlarge</code>) or minimum screen widths (such as
+<code>sw600dp</code>/<code>sw720</code>).</li>
+</ul>
+
+<h3>Related resources</h3>
+
+<div class="resource-widget resource-flow-layout col-13"
+  data-query="collection:distribute/essentials/tabletguidelines/extrascreen"
+  data-sortOrder="-timestamp"
+  data-cardSizes="6x3,6x3,6x3"
+  data-maxResults="6"></div>
+
+<div class="headerLine clearfloat"><h1 id="use-tablet-icons">4. Use Assets Designed for Tablet Screens</h1><hr></div>
+
+<div><img src="{@docRoot}design/media/devices_displays_density@2x.png"></div>
+
+<p>To ensure your app looks its best, provide icons and other bitmap
+assets for each density in the range commonly supported by tablets. Specifically, you should
+design your icons for the action bar, notifications, and launcher according to the
+<a href="{@docRoot}design/style/iconography.html">Iconography</a> guidelines and
+provide them in multiple densities, so they appear at the appropriate size on all screens
+without blurring or other scaling artifacts.</p>
+
+<p class="table-caption"><strong>Table 1</strong>. Raw asset sizes for icon types.<table>
+<tr>
+<th>Density</th>
+<th>Launcher</th>
+<th>Action Bar</th>
+<th>Small/Contextual</th>
+<th>Notification</th>
+</tr>
+<tr>
+<td><code>mdpi</code></td>
+<td>48x48 px</td>
+<td>32x32 px</td>
+<td>16x16 px</td>
+<td>24x24 px</td>
+</tr>
+<tr>
+<td><code>hdpi</code></td>
+<td>72x72 px</td>
+<td>48x48 px</td>
+<td>24x24 px</td>
+<td>36x36 px</td>
+</tr>
+<tr>
+<td><code>tvdpi</code></td>
+<td><em>(use hdpi)</em></td>
+<td><em>(use hdpi)</em></td>
+<td><em>(use hdpi)</em></td>
+<td><em>(use hdpi)</em></td>
+</tr>
+<tr>
+<td><code>xhdpi</code></td>
+<td>96x96 px</td>
+<td>64x64 px</td>
+<td>32x32 px</td>
+<td>48x48 px</td>
+</tr>
+<tr>
+<td><code>xxhdpi</code></td>
+<td>144x144 px</td>
+<td>96x96 px</td>
+<td>48x48 px</td>
+<td>72x72 px</td>
+</tr>
+
+</table>
+
+<p>
+  As a minimum, supply a version of each icon and bitmap asset that's optimized
+  for <strong>at least one</strong> the following common tablet screen
+  densities:
+</p>
+<ul>
+  <li><code>hdpi</code></li>
+  <li><code>xhdpi</code></li>
+  <li><code>xxhdpi</code></li>
+</ul>
+
+<p>Other tips:</p>
+
+<ul>
+<li>Use vector shapes when designing icons, so they scale without loss of either detail or edge crispness.</li>
+<li>Use density-specific <a
+href="{@docRoot}guide/topics/resources/providing-resources.html#AlternativeResources">
+resource qualifiers</a> to ensure that the proper icons are loaded for each screen density.</li>
+<li>Tablets and other large screen devices often request a launcher icon that is one density
+size larger than the device's actual density, so you should provide your launcher
+icon at the highest density possible. For example, if a tablet has an {@code xhdpi} screen,
+it will request the {@code xxhdpi} version of the launcher icon.</li>
+</ul>
+
+<h3>Related resources</h3>
+
+<div class="resource-widget resource-flow-layout col-13"
+  data-query="collection:distribute/essentials/tabletguidelines/assets"
+  data-sortOrder="-timestamp"
+  data-cardSizes="9x3"
+  data-maxResults="6"></div>
+
+<div class="headerLine clearfloat"><h1 id="adjust-font-sizes">5.
+Adjust Font Sizes and Touch Targets</h1><hr></div>
+
+<p>To make sure your app is easy to use on tablets, take some time to adjust the
+font sizes and touch targets in your tablet UI, for all of the screen
+configurations you are targeting. You can adjust font sizes through <a
+href="{@docRoot}guide/topics/ui/themes.html">styleable attributes</a> or <a
+href="{@docRoot}guide/topics/resources/more-resources.html#Dimension">dimension
+resources</a>, and you can adjust touch targets through layouts and bitmap
+drawables, as discussed above. </p>
+
+<p>Here are some considerations:</p>
+<ul>
+<li>Text should not be excessively large or small on tablet screen sizes and
+densities. Make sure that labels are sized appropriately for the UI elements they
+correspond to, and ensure that there are no improper line breaks in labels,
+titles, and other elements.</li>
+<li>The recommended touch-target size for onscreen elements is 48dp (32dp
+minimum) &mdash; some adjustments may be needed in your tablet UI. Read <a
+href="{@docRoot}design/style/metrics-grids.html">Metrics and
+Grids
+</a> to learn about implementation strategies to help most of your users. To
+meet the accessibility needs of certain users, it may be appropriate to use
+larger touch targets. </li>
+<li>When possible, for smaller icons, expand the touchable area to more than
+48dp using {@link android.view.TouchDelegate}
+or just centering the icon within the transparent button.</li>
+</ul>
+
+<h3>Related resources</h3>
+
+<div class="resource-widget resource-flow-layout col-13"
+  data-query="collection:distribute/essentials/tabletguidelines/fonts"
+  data-sortOrder="-timestamp"
+  data-cardSizes="9x3,9x3,6x3,6x3,6x3"
+  data-maxResults="6"></div>
+
+<div class="headerLine clearfloat"><h1 id="adjust-widgets">6. Adjust Sizes of Home Screen Widgets</h1><hr></div>
+
+<p>If your app includes a home screen widget, here are a few points to consider
+to ensure a great user experience on tablet screens: </p>
+
+<ul>
+<li>Set the widget's default height and width appropriately
+for tablet screens, as well as the minimum and maximum resize height and width.
+</li>
+<li>The widget should be resizable to 420dp or more, to span 5 or more home
+screen rows (if this is a vertical or square widget) or columns (if this is a
+horizontal or square widget). </li>
+<li>Make sure that 9-patch images render correctly.</li>
+<li>Use default system margins.</li>
+<li>Set the app's <code>targetSdkVersion</code> to 14 or higher, if
+possible.</li>
+</ul>
+
+<h3>Related resources</h3>
+
+<div class="resource-widget resource-flow-layout col-13"
+  data-query="collection:distribute/essentials/tabletguidelines/widgets"
+  data-sortOrder="-timestamp"
+  data-cardSizes="6x3"
+  data-maxResults="6"></div>
+
+
+<div class="headerLine clearfloat"><h1 id="offer-full-feature-set">7. Full Feature Set for Tablet Users</h1><hr></div>
+
+<div class="centered-full-image" style="width:600px;margin:1.5em"><img src="{@docRoot}images/gp-tablets-full-feature-set.png" alt="Tablet feature sets"></div>
+
+<p>Let your tablet users experience the best features of your app. Here are
+some recommendations:</p>
+
+<ul>
+  <li>Design your app to offer at least the same set of features on tablets as
+  it does on phones.
+  </li>
+
+  <li>In exceptional cases, your app might omit or replace certain features on
+  tablets if they are not supported by the hardware or use-case of most
+  tablets. For example:
+    <ul>
+      <li>If the handset uses telephony features but telephony is not available
+      on the current tablet, you can omit or replace the related functionality.
+      </li>
+
+      <li>Many tablets have a GPS sensor, but most users would not normally
+      carry their tablets while running. If your phone app provides
+      functionality to let the user record a GPS track of their runs while
+      carrying their phones, the app would not need to provide that
+      functionality on tablets because the use-case is not compelling.
+      </li>
+    </ul>
+  </li>
+
+  <li>If you will omit a feature or capability from your tablet UI, make sure
+  that it is not accessible to users or that it offers “graceful degradation”
+  to a replacement feature (also see the section below on hardware features).
+  </li>
+</ul>
+
+<div class="headerLine clearfloat"><h1 id="android-versions">8. Target Android Versions Properly</h1><hr></div>
+
+<p>
+  To ensure the broadest possible distribution to tablets, make sure that your
+  app properly targets the Android versions that support tablets. Initial
+  support for tablets was added in <a href=
+  "{@docRoot}about/versions/android-3.0.html">Android 3.0</a> (API level 11).
+  Unified UI framework support for tablets, phones, and other devices was
+  introduced in <a href="{@docRoot}about/versions/android-4.0.html">Android
+  4.0</a>
+</p>
+
+<p>
+  You can set the app's range of targeted Android versions in the manifest
+  file, in the <a href=
+  "{@docRoot}guide/topics/manifest/uses-sdk-element.html"><code>&lt;uses-sdk&gt;</code></a>
+  element. In most cases, you can target Android versions properly by setting
+  the element's <code>targetSdkVersion</code> attribute to the highest API
+  level available.
+</p>
+
+<p style="margin-bottom:.5em;">
+  At a minimum, check the <a href=
+  "{@docRoot}guide/topics/manifest/uses-sdk-element.html"><code>&lt;uses-sdk&gt;</code></a>
+  element to make sure that:
+</p>
+
+<ol style="list-style-type:lower-alpha;margin-top:0em;">
+  <li>
+    <code>targetSdkVersion</code> is declared with value 11 or higher (14 or
+    higher is recommended), OR
+  </li>
+
+  <li>
+    <code>minSdkVersion</code> is declared with value 11 or higher.
+  </li>
+
+  <li>If a <code>maxSdkVersion</code> attribute is declared, it must have a
+  value of 11 or higher. Note that, in general, the use of
+  <code>maxSdkVersion</code> is <em>not recommended</em>.
+  </li>
+</ol>
+
+<h3>Related resources</h3>
+
+<div class="resource-widget resource-flow-layout col-13"
+  data-query="collection:distribute/essentials/tabletguidelines/versions"
+  data-sortOrder="-timestamp"
+  data-cardSizes="6x3"
+  data-maxResults="6"></div>
+
+<div class="headerLine clearfloat"><h1 id="hardware-requirements">9. Declare Hardware Feature Dependencies Properly</h1><hr></div>
+
+<p>
+  Handsets and tablets typically offer slightly different hardware support for
+  sensors, camera, telephony, and other features. For example, many tablets are
+  available in a "Wi-Fi" configuration that does not include telephony support.
+</p>
+
+<p>
+  So that you can distribute a single APK broadly across your full customer
+  base of phones and tablets, make sure that your app doesn't declare
+  requirements for hardware features that aren't commonly available on tablets.
+  Instead, properly declare the hardware features as <em>not required</em> in the app
+  manifest, as described below.
+</p>
+
+<ul>
+<li>In your app manifest, locate any <a href="{@docRoot}guide/topics/manifest/uses-feature-element.html"><code>&lt;uses-feature&gt;</code></a>
+elements. In particular, look for hardware features that might not be
+available on some tablets, such as:
+
+<ul>
+<li><code>android.hardware.telephony</code></li>
+<li><code>android.hardware.camera</code> (refers to back camera), or</li>
+<li><code>android.hardware.camera.front</code></li>
+</ul></li>
+
+<li>Declare the <a href="{@docRoot}guide/topics/manifest/uses-feature-element.html"><code>&lt;uses-feature&gt;</code></a>
+elements as <em>not required</em> by including the <code>android:required=”false”</code>
+attribute.
+
+<p>
+  For example, here's the proper way to declare a dependency on
+  <code>android.hardware.telephony</code>, such that you can still
+  distribute the app broadly, even to devices that don't offer telephony:
+</p>
+
+<pre>&lt;uses-feature android:name="android.hardware.telephony" android:required="false" /&gt;</pre></li>
+
+<li>Similarly, check the manifest for <a href="{@docRoot}guide/topics/manifest/permission-element.html"><code>&lt;permission&gt;</code></a> elements that 
+<a href="{@docRoot}guide/topics/manifest/uses-feature-element.html#permissions">imply hardware
+feature requirements</a> that not be appropriate for tablets. If you find such
+permissions, make sure to explicitly declare a corresponding
+<code>&lt;uses-feature&gt;</code> element for the features and includes the
+<code>android:required=”false”</code> attribute.</li>
+</ul>
+
+
+<p>
+  After declaring hardware features as <em>not required</em>, make sure to test
+  your app on a variety of devices. The app should function normally when the
+  hardware features it uses are not available, and it should offer "graceful
+  degradation" and alternative functionality where appropriate.
+</p>
+
+<p>
+  For example, if an app normally uses GPS to set the location but GPS is not
+  supported on the device, the app could let the user set the location manually
+  instead. The app can check for device hardware capabilities at runtime and handle
+  as needed.
+</p>
+
+<h3>Related resources</h3>
+
+<div class="resource-widget resource-flow-layout col-13"
+  data-query="collection:distribute/essentials/tabletguidelines/hardware"
+  data-sortOrder="-timestamp"
+  data-cardSizes="9x3"
+  data-maxResults="6"></div>
+
+<div class="headerLine clearfloat"><h1 id="support-screens">10. Declare Support for Tablet Screens</h1><hr></div>
+
+<p>To ensure that you can distribute your app to a broad range of tablets, your app should
+declare support for tablet screen sizes in its manifest file, as follows:</p>
+
+<ul>
+  <li>A
+  <a href="{@docRoot}guide/topics/manifest/supports-screens-element.html"><code>&lt;supports-screens&gt;</code></a>
+  element, if declared, must not specify <code>android:largeScreens="false"</code>
+  or <code>android:xlargeScreens="false"</code>.</li>
+  <li>For apps targeting <code>minSdkVersion</code> value less than 13, a
+  <a href="{@docRoot}guide/topics/manifest/supports-screens-element.html"><code>&lt;supports-screens&gt;</code></a>
+  element must be declared with both <code>android:largeScreens="true"</code> and
+  <code>android:xlargeScreens="true"</code>.</li>
+</ul>
+
+<p>If the app declares a
+<a href="{@docRoot}guide/topics/manifest/compatible-screens-element.html"><code>&lt;compatible-screens&gt;</code></a>
+element in the manifest, the element should include attributes that specify
+<em>all of the size and density combinations for tablet screens</em> that the
+app supports. Note that, if possible, you should avoid using the
+<a href="{@docRoot}guide/topics/manifest/compatible-screens-element.html"><code>&lt;compatible-screens&gt;</code></a>
+element in your app.</p>
+
+<h3>Related resources</h3>
+
+<div class="resource-widget resource-flow-layout col-13"
+  data-query="collection:distribute/essentials/tabletguidelines/tabletscreens"
+  data-sortOrder="-timestamp"
+  data-cardSizes="9x3,6x3,6x3"
+  data-maxResults="6"></div>
+
+
+<div class="headerLine clearfloat"><h1 id="google-play">11. Showcase Your Tablet UI in Google Play</h1><hr></div>
+
+<p>
+  After you've done the work to create an rich, optimized UI for your tablet
+  app, make sure that you let your customers know about it! Here are some key
+  ways to promote your tablet app to users on Google Play.
+</p>
+
+<div><img class="border-img" src="{@docRoot}images/gp-tablet-quality-4.jpg"></div>
+
+
+<h4>
+  Upload screenshots of your tablet UI
+</h4>
+
+<p>
+  Tablet users want to know what your app is like on a tablet device, not on a
+  phone. If you developed a tablet app, make sure to upload screenshots
+  of your tablet UI to the Google Play Developer Console. Here are some guidelines:
+  </p>
+
+<ul style="margin-top:0;">
+  <li>Show the core functionality of your app, not a
+  startup or sign-in page. Wherever users will spend most of their time, that's
+  what you should show in your screenshots.
+  </li>
+
+  <li>Add screenshots taken on both 7-inch and 10-inch tablets.
+  </li>
+
+  <li>Add screenshots taken in both landscape and
+  portrait orientations, if possible.
+  </li>
+
+  <li>Use screen captures if possible. Avoid showing actual device hardware in your
+  screenshots.</li>
+
+  <li>The recommended resolution of your tablet screenshots is <strong>1280 x 720</strong>
+  or higher in each orientation.
+  </li>
+
+  <li>Upload as many as 8 screenshots of your tablet UI for 7-inch tablets
+  and an additional 8 for 10-inch tablets.
+  </li>
+</ul>
+
+<h4>
+  Update your app description and release notes
+</h4>
+
+<ul>
+  <li>In your app description, make sure to highlight that your app offers
+  tablet-optimized UI and great features for tablet users. Add some
+  detail about how your tablet UI works and why users will like it.
+  </li>
+
+  <li>Include information about tablet support in the app's release notes and
+  update information.
+  </li>
+</ul>
+
+<h4>
+  Update your promotional video
+</h4>
+
+<p>
+  Many users view an app's promotional video to get an idea of what the app is
+  like and whether they'll enjoy it. For tablet users, capitalize on this
+  interest by highlighting your app's tablet UI in your promotional video. Here
+  are some tips and guidelines:
+</p>
+
+<ul>
+  <li>Add one or more shots of your app running on a tablet. To engage with
+  tablet users most effectively, it's recommended that you promote your tablet
+  UI in approximately equal proportion to your phone UI.
+  </li>
+
+  <li>Show your tablet UI as early as possible in the video. Don't assume that
+  tablet users will wait patiently through a feature walkthrough on a phone UI.
+  Ideally, you should engage them immediately by showing the tablet UI within
+  the first 10 seconds, or at the same point that you introduce the phone UI.
+  </li>
+
+  <li>To make it clear that you are showing a tablet UI, include shots of your
+  app running on a hand-held tablet device.
+  </li>
+
+  <li>Highlight your app's tablet UI in the video's narrative or voiceover.
+  </li>
+</ul>
+
+<h4>
+  Feature your tablet UI in your promotional campaigns
+</h4>
+
+<p>
+  Make sure to let tablet users know about your tablet UI in your promotional
+  campaigns, web site, social posts, advertisements, and elsewhere. Here are
+  some suggestions:
+</p>
+
+<ul>
+  <li>Plan a marketing or advertising campaign that highlights the use of your
+  app on tablets.</li>
+
+  <li>Show your tablet app at its best in your promotional campaigns&mdash;use the <a href=
+  "{@docRoot}distribute/tools/promote/device-art.html">Device Art Generator</a> to
+  quickly generate a high-quality promotional image of your app running on a
+  7-inch or 10-inch tablet, in the orientation of your choice, with or without
+  drop-shadow and screen glare. It's as simple as capture, drag, and drop.
+  </li>
+
+  <li>Include a Google Play badge in your online promotions to let users link
+  directly to your app's store listing. You can generate a badge in a variety
+  of languages using the <a href=
+  "{@docRoot}distribute/tools/promote/badges.html">Badge Generator</a>.
+  </li>
+</ul>
+
+<h3>Related resources</h3>
+
+<div class="resource-widget resource-flow-layout col-13"
+  data-query="collection:distribute/essentials/tabletguidelines/showcase"
+  data-sortOrder="-timestamp"
+  data-cardSizes="9x3,9x3,9x3,9x3"
+  data-maxResults="6"></div>
+
+<div class="headerLine clearfloat">
+  <h1 id="google-play-best-practices">
+    12. Follow Best Practices for Publishing in Google Play
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  Here are some best practices for delivering a successful tablet app on Google
+  Play.
+</p>
+
+<div>
+  <img class="border-img" src="{@docRoot}images/gp-tablet-quality-5.jpg" style=
+  "1px solid #ddd">
+</div>
+
+<h4 id="google-play-optimization-tips">
+  Check out your app's Optimization Tips
+</h4>
+
+<p>The Google Play Developer Console now offers an Optimization Tips page that
+lets you quickly check how your app is doing against basic guidelines for tablet app
+distribution and quality. To visit the page, sign into the Developer Console,
+load the app from All Applications, and click Optimization Tips in
+the left navigation.</p>
+
+<div class="sidebox-wrapper">
+<div class="sidebox">
+<h2>How to send feedback</h2>
+
+<p>Please use the link below to send
+feedback or request a manual review of your Optimization Tips.</p>
+
+<p>Make sure to read the relevant sections of the Tablet App Quality
+Guidelines prior to sending feedback.</p>
+
+<p><strong><a href="https://support.google.com/googleplay/android-developer/contact/tabletq"
+target="_googleplay" style="white-space:nowrap">Designed for Tablets Contact Form &raquo;</a></strong></p>
+</div>
+</div>
+
+<p>The Developer Console creates your app's Optimization Tips page
+by running a series of checks to verify basic quality
+criteria. If it finds any issues, it alerts you to them as "To Do"
+items in the Optimization Tips page.</p>
+
+<p>If you've developed a tablet experience for your app, make sure
+to visit the Optimization Tips page to see how your app is doing
+against the basic checks.  If there are any issues listed, we
+recommend addressing them in your app and uploading a new binary for
+distribution, if needed. </p>
+
+<p>If the Optimization Tips page lists "To Do" issues that you feel don't
+apply to your app or affect its quality on tablets, please notify us
+using the <a href="https://support.google.com/googleplay/android-developer/contact/tabletq"
+target="_googleplay" style="white-space:nowrap">Designed for Tablets Contact Form &raquo;</a>. We
+will review your app and update your Optimization Tips page as
+appropriate.</p>
+
+
+<h4>Confirm the app's filtering</h4>
+
+<p>
+  After you've uploaded the app to the <a href=
+  "https://play.google.com/apps/publish/">Developer Console</a>, check the
+  APK's Supported Devices list to make sure that the app is not filtered from
+  tablet devices that you want to target.
+</p>
+
+<h4>Distribute as a single APK</h4>
+
+<p>
+  It's recommended that you publish your app as a single APK for all screen
+  sizes (phones and tablets), with a single Google Play listing. This approach
+  has several important advantages.
+</p>
+
+<ul style="margin-top:.25em;">
+  <li>Easier for users to find your app from search, browsing, or promotions
+  </li>
+
+  <li>Easier for users to restore your app automatically if they get a new
+  device.
+  </li>
+
+  <li>Your ratings and download stats are consolidated across all devices.
+  </li>
+
+  <li>Publishing a tablet app in a second listing can dilute ratings for your
+  brand.
+  </li>
+</ul>
+
+<p>
+  If necessary, you can alternatively choose to deliver your app using <a href=
+  "{@docRoot}google/play/publishing/multiple-apks.html">Multiple APK Support</a>,
+  although in most cases using a single APK to reach all devices is strongly
+  recommended.
+</p>
+
+<h3 class="clearfloat">Related resources</h3>
+<div class="resource-widget resource-flow-layout col-13"
+  data-query="collection:distribute/essentials/tabletguidelines/googleplay"
+  data-sortOrder="-timestamp"
+  data-cardSizes="9x3"
+  data-maxResults="6"></div>
+
+
+<div class="headerLine clearfloat">
+  <h1 id="test-environment">
+    Setting Up a Test Environment for Tablets
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  Assess the quality of your app on tablets — both for core app quality and
+  tablet app quality &mdash; with a suitable hardware or emulator environment
+  for testing.
+</p>
+
+<p>
+  Compared to the <a href=
+  "{@docRoot}distribute/essentials/quality/core.html#test-environment">recommended
+  test environment</a> for testing against the core app quality criteria,
+  include mid-size tablets and tablets with more or fewer hardware/software
+  features.
+</p>
+
+<p class="table-caption"><strong>Table 1</strong>. A typical tablet test environment might
+include one or two devices from each row in the table below, with one of the
+listed platform versions, screen configurations, and hardware feature configurations.</p>
+
+<table>
+<tr>
+<th>Type</th>
+<th>Size</th>
+<th>Density</th>
+<th>Version</th>
+<th>AVD Skin</th>
+</tr>
+
+<tr>
+<td>7-inch tablet</td>
+<td><span style="white-space:nowrap"><code>large</code> or</span><br /><code>-sw600</code></td>
+<td><code>hdpi</code>,<br /><code>tvdpi</code></td>
+<td>Android 4.0+ (API level 14 and higher)</td>
+<td>WXGA800-7in</td>
+</tr>
+<tr>
+<td><span style="white-space:nowrap">10-inch</span> tablet</td>
+<td><span style="white-space:nowrap"><code>xlarge</code> or</span><br /><code>-sw800</code></td>
+<td><code>mdpi</code>,<br /><code>hdpi</code>,<br /><code>xhdpi</code></td>
+<td>Android 3.2+ (API level 13 and higher)</td>
+<td>WXGA800</td>
+</tr>
+</table>
+
+<div class="headerLine clearfloat"><h1 id="related-resources">Related Resources</h1><hr></div>
+
+<div class="resource-widget resource-flow-layout col-13"
+  data-query="collection:distribute/essentials/tabletguidelines"
+  data-sortOrder="-timestamp"
+  data-cardSizes="9x3"
+  data-maxResults="6"></div>
\ No newline at end of file
diff --git a/docs/html/distribute/googleplay/about.jd b/docs/html/distribute/googleplay/about.jd
new file mode 100644
index 0000000..cf0c6d2
--- /dev/null
+++ b/docs/html/distribute/googleplay/about.jd
@@ -0,0 +1,369 @@
+page.title=The Google Play Opportunity
+meta.tags="visibility, growth, distributing"
+page.tags="play, apps, distributing, publishing"
+page.metaDescription=Billons of downloads a month and growing. Get your apps in front of users at Google's scale.
+page.image=/distribute/images/about-play.jpg
+
+@jd:body
+
+    <div id="qv-wrapper">           
+  <div id="qv">
+  <h2>About Google Play</h2>
+    <ol style="list-style-type:none;">
+      <li><a href="#reach">Worldwide Reach, Rapid Growth</a></li>
+      <li><a href="#ratings-reviews">User Ratings and Reviews</a></li>
+      <li><a href="#category-browsing">Category Browsing</a></li>
+      <li><a href="#search">Search</a></li>
+      <li><a href="#top-charts-and-lists">Top Charts and Lists</a></li>
+      <li><a href="#featured-staff-picks">Featured, Staff Picks, Collections, and Badges</a></li>
+      <li><a href="#product-detail-pages">Store Listing Pages</a></li>
+      <li><a href="#related-resources">Related Resources</a></li>
+    </ol>
+  </div>
+</div>
+
+<p>
+  Google Play is the premier store for distributing Android apps. When you
+  publish on Google Play, you put your apps in front of Android's huge base of
+  active customers, in more than 130 countries and territories across the
+  world.
+</p>
+
+<div>
+  <img src="{@docRoot}images/gp-about-0.jpg" alt="Google Play on an Android Tablet"
+  style="width:480px;position:relative" />
+</div>
+
+<p>
+  Google Play is a central part of the Android experience. New users
+  personalize their devices with apps, games, and other Google Play content.
+  Existing users return regularly to see what's trending and new. Downloading
+  new apps is extremely convenient and fast&mdash; Google Play pushes apps to
+  the user's devices instantly, over the air.
+</p>
+
+<p>
+  Google Play is also a top destination for web users. Anyone with a browser
+  can explore Google Play on the web. Android users can even buy and install
+  the apps they want and Google Play pushes them automatically to their devices
+  with no cables required.
+</p>
+
+<p>
+  The accessibility and convenience of the Google Play web site give you new
+  ways to drive traffic to your products from many sources, such as online ads,
+  web search and cross-linking. Google Play is designed to connect users with
+  great apps and games. It provides key channels to get your app noticed and
+  gain traction in the marketplace.
+</p>
+
+<div class="headerLine">
+  <h1 id="ratings-reviews">
+    User Ratings and Reviews
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  Prospective users look at ratings and reviews as key benchmarks of app
+  quality. By rating apps from one to five stars and posting reviews, Android
+  users show their appreciation for the apps they have downloaded.
+</p>
+
+<p>
+  <strong>Your app's rating is one of the most important factors influencing
+  its ranking</strong> in the Google Play lists and search results. It's also
+  one of the key metrics that the editorial staff looks for when curating apps
+  and games for promotion in the store.
+</p>
+
+<div class="img" style="padding: 1em auto;width:96%;">
+  <img src="{@docRoot}images/gp-rating-web.png" style="border:1px solid #ddd;">
+</div>
+
+<div class="headerLine">
+  <h1 id="category-browsing">
+    Category Browsing
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  When you publish an app in Google Play, you pick the category where you want
+  users to find your app. More than 30 categories are available. Inside each
+  category, apps are ranked based on a combination of ratings, reviews,
+  downloads, country, and other factors.
+</p>
+
+<div class="headerLine">
+  <h1 id="search">
+    Search
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  Search on Google Play lets users pinpoint an app or game quickly. Search uses
+  powerful heuristics to suggest terms as the user types, and it offers direct
+  links to apps as suggestions. In results, users find the most relevant, most
+  popular apps at the top.
+</p>
+
+<div class="headerLine">
+  <h1 id="top-charts-and-lists">
+    Top Charts and Lists
+  </h1>
+
+  <hr>
+</div>
+
+<div class="figure">
+  <img src="{@docRoot}images/gp-about-top.jpg">
+</div>
+
+<p>
+  Top charts keep users in touch with what’s popular and trending with Android
+  users, right from the Apps and Games home pages. The charts stay fresh,
+  updating several times each day based on recent download activity. As an
+  app's ratings and download activity grow, it can move up in the charts.
+</p>
+
+<p>
+  To make the charts as relevant as possible for users across the world, they
+  are also country-specific in Google Play's most popular countries. As your
+  apps get traction and build momentum in downloads and ratings, they’ll climb
+  one or more of the top charts and gain even more exposure.
+</p>
+
+<table style="width:50%;">
+  <tr>
+    <td>
+      Top Free
+    </td>
+    <td>
+      Free apps and free games lists
+    </td>
+  </tr>
+
+  <tr>
+    <td>
+      Top Paid
+    </td>
+    <td>
+      Paid apps and paid games lists
+    </td>
+  </tr>
+
+  <tr>
+    <td>
+      Top Grossing
+    </td>
+    <td>
+      Gross proceeds, free or paid
+    </td>
+  </tr>
+
+  <tr>
+    <td>
+      Top New Free
+    </td>
+    <td>
+      Less than 30 days old
+    </td>
+  </tr>
+
+  <tr>
+    <td>
+      Top New Paid
+    </td>
+    <td>
+      Less than 30 days old
+    </td>
+  </tr>
+
+  <tr>
+    <td>
+      Trending
+    </td>
+    <td>
+      New arrivals growing quickly in installs
+    </td>
+  </tr>
+</table>
+
+<div class="headerLine">
+  <h1 id="featured-staff-picks">
+    Featured, Staff Picks, Collections, and Badges
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  The Google Play editorial team is dedicated to bringing the best apps to the
+  attention of users and setting the tone for app quality throughout the store.
+  It constantly reviews apps from across Google Play to find not only the
+  best-known apps and games, but also the "diamonds in the rough" that they
+  want more people to see. The team promotes great apps in the
+  <em>Featured</em>, <em>Staff Picks</em>, and other collections.
+</p>
+
+<p>
+  You can't nominate your app for featuring, but the team is always monitoring
+  Google Play for great apps. If you build an app that users love and that
+  looks great on Android devices, the editorial team will notice.
+</p>
+
+<h3 id="featured-staff-picks2">
+  Featured and Staff Picks
+</h3>
+
+<p>
+  Each week the Google Play editorial staff selects a new set of apps to
+  promote in its popular <em>Featured</em> and <em>Staff Picks</em>
+  collections.
+</p>
+
+<p>
+  The <em>Featured</em> collections highlight the latest and greatest app and
+  game titles available for Android. The list also includes the best and most
+  popular apps in the top categories are also featured. <em>Staff Picks</em>
+  collects all recently featured apps and games on Google Play. To focus on
+  tablet users, A special <em>Staff Picks</em> collection highlights the best
+  apps for Android tablets.
+</p>
+
+<table style="text-align:center;margin:1.5em 0;">
+  <tr>
+    <td style="border:none;">
+      <img src="{@docRoot}images/gp-about-picks1.jpg">
+      <p>
+        Featured
+      </p>
+    </td>
+    <td style="border:none;">
+      <img src="{@docRoot}images/gp-about-picks2.jpg">
+      <p>
+        Collection
+      </p>
+    </td>
+    <td style="border:none;">
+      <img src="{@docRoot}images/gp-about-picks3.jpg">
+      <p>
+        Editors' Choice
+      </p>
+    </td>
+  </tr>
+</table>
+
+<h3 id="collections">
+  App collections
+</h3>
+
+<p>
+  From time to time the editorial staff puts together a collection of apps and
+  games based on a theme or seasonal event. Users frequently use these lists to
+  select apps, attracted by the timeliness of the collection.
+</p>
+
+<p>
+  The editorial staff chooses apps for collection promotions &mdash;
+  high-quality apps that show the best of Android on phones and tablets. The
+  staff also looks for apps that can make an interesting or unique contribution
+  to the collection as a whole.
+</p>
+
+<h3 id="editors-choice">
+  <img style="margin-right:.25em;margin-bottom:.5em;" src=
+  "{@docRoot}images/editorschoice_ann.png"> Editors' Choice
+</h3>
+
+<p>
+  <em>Editors’ Choice</em> is a curated collection of apps that highlights some
+  of the very best apps available on Android. Editors choose these apps for
+  quality and great user interface, long-term popularity and innovative use of
+  Android features.
+</p>
+
+<p>
+  Apps chosen for <em>Editors’ Choice</em> also receive a badge that is
+  displayed wherever the app name is seen in Google Play.
+</p>
+
+<h3 id="top-developer">
+  <img style="margin-right:.25em;margin-bottom:.5em;" src=
+  "{@docRoot}images/topdev_ann.png"> Top Developer
+</h3>
+
+<p>
+  Top Developer is a badge recognizing established, respected developers for
+  their commitment to launching high-quality and innovative apps on Android.
+  The Google Play editorial staff awards a Top Developer badge from
+  time-to-time based on the cumulative work of the developer.
+</p>
+
+<p>
+  The Top Developer badge appears next to the developer name wherever it is
+  displayed in Google Play. The badge means long-term recognition of all of the
+  developer’s apps. It signifies an additional level of trust and confidence
+  users have in a developer’s products.
+</p>
+
+<div class="headerLine">
+  <h1 id="product-detail-pages">
+    Store Listing Pages
+  </h1>
+
+  <hr>
+</div>
+
+<div class="figure">
+  <img src="{@docRoot}images/gp-about-listing.jpg">
+</div>
+
+<p>
+  Your app’s Google Play storefront is its <em>store listing page</em>: a rich
+  and colorful page that lets you promote your app, highlight its ratings and
+  reviews, and show what your app can do.
+</p>
+
+<p>
+  Your store listing is where your users come to find out everything about your
+  app. When they see your app listed in search results, top charts, category
+  listings, and collections, one tap takes them directly to your store listing.
+</p>
+
+<p>
+  Manage your product details page through the <a href=
+  "https://play.google.com/apps/publish/">Google Play Developer Console</a>
+  from any web browser. Sign in to upload or update your brand assets, and
+  enter your product details in the languages of your markets.
+</p>
+
+<p>
+  When you publish, Google Play adds your app’s ratings, reviews, links to your
+  other products, and more. It also makes sure your store listing page looks
+  great on phones, tablets, and in a web browser.
+</p>
+
+<p>
+  You can link web users directly to your product details page from outside
+  Google Play, such as from your web site, an ad campaign, reviews, social
+  media posts, and more. See <a href=
+  "{@docRoot}distribute/tools/promote/linking.html">Linking to Your
+  Products</a> to find out how.
+</p>
+
+<div class="headerLine clearfloat">
+<h1>Related Resources</h1><hr>
+</div>
+
+<div class="resource-widget resource-flow-layout col-13"
+  data-query="collection:distribute/googleplay"
+  data-sortOrder="-timestamp"
+  data-cardSizes="9x3"
+  data-maxResults="4"></div>
+    </div>
\ No newline at end of file
diff --git a/docs/html/distribute/googleplay/about/distribution.jd b/docs/html/distribute/googleplay/about/distribution.jd
deleted file mode 100644
index 8020110..0000000
--- a/docs/html/distribute/googleplay/about/distribution.jd
+++ /dev/null
@@ -1,167 +0,0 @@
-page.title=Distribution Control
-page.metaDescription=Reach the users you want, whenever you want.
-
-@jd:body
-
-<p>Deliver your apps to the users you want, on the devices you want, on <em>your</em> schedule. </p>
-
-<h2 id="instant">Instant publishing, instant updates</h2>
-
-<p>On Google Play, you can publish your products to customers instantly. Just
-upload and configure your product in the <span style="font-weight:500;">Google Play Developer Console</span>
-and press the Publish button&mdash;your app appears in the store listings within
-hours, not weeks.</p>
-
-<p>Once your app is published, you can update it as often as you want. You can
-change prices, configuration, and distribution options at any time through the
-Google Play Developer Console, without needing to update your app
-binary.</p>
-
-<p>Later, as you add features or address code issues, you can publish an updated
-binary at any time. Google Play makes the new version available almost immediately and
-notifies existing customers that an update is ready for download. To streamline
-the rollout across your customer base, Google Play also lets users accept
-automatic updates of your app, so that your updates are delivered and installed
-as soon as you publish them.</p>
-
-
-<h2 id="targeting">Reaching the customers you want</h2>
-
-<div class="figure-right" style="width:400px;">
-<img src="{@docRoot}images/gp-dc-countries.png" class="frame">
-</div>
-
-<p>Google Play does more than connect your app with users&mdash;it helps you
-reach the broadest possible distribution across the Android ecosystem, while
-making sure that your app is only available to the audience that you want to
-reach.</p>
-
-<h3 id="geotargeting">Geographic targeting</h3>
-
-<p>You can use controls in the Google Play Developer Console to easily
-manage the geographic distribution of your apps, without any changes in your
-application binary. You can specify which countries and territories you want to
-distribute to, and even which carriers (for some countries). </p>
-
-<p>When users visit the store, Google Play makes sure that they are in one of
-your targeted countries before downloading your app. You can change your country
-and carrier targeting at any time just by saving changes in the Google Play
-Developer Console.</p>
-
-<div class="figure-right" style="width:400px;">
-<img src="{@docRoot}images/gp-supported-dev-requirements.png" class="frame">
-</div>
-
-<p>To help you market to users around the world, you
-can <a href="{@docRoot}distribute/googleplay/publish/preparing.html#localize">localize
-your store listing</a>, including app details and description,
-promotional graphics, screenshots, and more.</p>
-
-<h3 id="captargeting">Capabilities targeting</h3>
-
-<p>Google Play also lets you control distribution according to device features
-or capabilities that your app depends on. There are several types of
-dependencies that the app can define in its manifest, such as hardware features,
-OpenGL texture compression formats, libraries, Android platform versions, and
-others.</p>
-
-<p>When you upload your app, Google Play reads the dependencies and sets up any
-necessary distribution rules. For technical information about declaring
-dependencies, read <a href="{@docRoot}google/play/filters.html">Filters on 
-Google Play</a>. </p>
-
-<p>For pinpoint control over distribution, Google Play lets you see all of the
-devices your app is available to based on its dependencies (if any). From the
-Google Play Developer Console, you can list the supported devices and
-even exclude specific devices if needed.</p>
-
-<h2 id="stats">Statistics for analyzing installs and ratings</h2>
-
-<p>Once you’ve published your app, Google Play makes it easy to see how it’s
-doing. The Google Play Developer Console gives you access to a variety
-of anonymized statistics and custom charts that show you the app's installation
-performance and ratings.</p>
-
-<p>You can view data and charts for active, daily, and total installs 
-per unique devices or users, as well as upgrades and uninstalls.
-You can also view the app's daily average user rating and its cumulative
-user rating. To help you analyze the data, you can view install
-and ratings statistics across a variety of different dimensions such as Android 
-version, device, country, app version, and carrier.</p>
-
-<div class="figure-left">
-  <img src="{@docRoot}images/gp-dc-stats-mini.png" class="frame">
-</div>
-<p>You can see your app statistics on timeline charts, for
-all metrics and dimensions. At a glance, the charts highlight your app’s
-installation and ratings peaks and longer-term trends, which you can correlate
-to promotions, app improvements, or other factors. You can even focus in on
-data inside a dimension by highlighting specific data points (such as
-individual platform versions or languages) on the timeline.</p>
-
-<p>So that you can “take your data with you”, you can download all of your
-installation data as a CSV file for viewing in the business program of your
-choice.</p>
-
-
-<h2 id="advanced">Advanced delivery options</h2>
-
-<p>Google Play offers convenient options for managing how your apps are
-delivered to users.</p>
-
-<h3 id="abc">Alpha and beta testing, staged rollouts</h3>
-
-<p>It's always valuable to get real-world feedback from users, especially before
-launch. Google Play makes it easy to distribute pre-release versions of your app
-to alpha and beta test groups anywhere in the world. You can start with a small
-group of alpha testers, then move to a larger group of beta testers. Once users
-are added, they access your app's store listing and install the app. User
-feedback from alpha and beta testers goes directly to you and is not posted as
-public reviews. </p>
-
-<p>To help you ensure quality and protect your app ratings, you can choose a
-staged rollout when launching an app or an update. With staged rollout, you
-distribute the production version of your app to a percentage of users. You can
-adjust the percentage as you go, starting small and increasing until your app is
-available to all users.</p>
-
-<h3 id="multiple-apk">Multiple APK support</h3>
-
-<p>In most cases, it’s easy to create an app that supports all of your targeted
-screen sizes and platform versions from a single APK. Distributing a single APK
-to all of your users is a highly recommended approach, because it’s the easiest
-way to manage and maintain the app. If you need to deliver a different APK to
-devices, Google Play provides a way to do that. </p>
- 
-<p>An option called Multiple APK support lets you create multiple APK packages
-that use the same package name but differ in their OpenGL texture compression
-formats, screen-size support, or Android platform versions supported. You can
-upload all of the APKs to Google Play under a single product listing and Google
-Play selects the best APK to deliver to users, based on the characteristics of
-their devices.  </p>
-
-<p>The APK Expansion Files option lets you upload up to two secondary downloads
-for each published APK, including multiple APKs. Each of the two expansion files
-can be up to 2GB each and can contain any type of code or assets. When you
-upload the expansion files, Google Play hosts them for free and handles the
-download of the files as part of the normal APK installation.</p>
-
-<h2 id="licensing">Protecting your app</h2>
-
-<p>Google Play provides two key features to help you protect your application
-against piracy &mdash; Google Play Licensing and app encryption.</p>
-
-<p> Google Play Licensing is a network-based service that you implement in your
-app. The service lets your app query a trusted licensing server at runtime, to
-determine whether the app is licensed to the current device user. You can use
-the licensing service to protect any app, even apps that you distribute for
-free. For an overview of the service, see <a
-href="{@docRoot}google/play/licensing/index.html">Application
-Licensing</a>.</p>
-
-<p>Additionally, Google Play offers app encryption to help protect your priced
-apps. When delivering your priced apps to devices running Android 4.1 or higher,
-Google encrypts the app binary so that it can be run only by the user who
-downloaded it, on the device to which it was originally downloaded. Your priced
-apps benefit from app encryption automatically &mdash; there's no extra
-development work or configuration needed.</p>
diff --git a/docs/html/distribute/googleplay/about/monetizing.jd b/docs/html/distribute/googleplay/about/monetizing.jd
deleted file mode 100644
index 9a5c6d7..0000000
--- a/docs/html/distribute/googleplay/about/monetizing.jd
+++ /dev/null
@@ -1,162 +0,0 @@
-page.title=Flexible Monetizing and Business Tools
-page.metaDescription=
-
-@jd:body
-   
-<div style="float:right;margin-left:18px;padding:1.5em;">
-<img src="{@docRoot}images/gp-details-ww.png" style="width:180px">
-<img src="{@docRoot}images/gp-details-ww-purchase.png" style="width:180px">
-</div>
-    
-<p>Sell your app in more than 130 countries. Flexible monetization options with
-in-app purchase, subscriptions, and more. </p>
-
-<h2>Streamlined purchase flow for users</h2>
-
-<p>When users find your app, they can purchase it instantly with a streamlined,
-consistent purchasing process and convenient payment methods.</p>
-
-<h3>Instant purchase from device or web</h3>
-
-<p>Google Play makes it fast and easy for your customers to buy your products,
-whether from a phone, a tablet, or a desktop computer. When users find an app or
-game that they want to buy, they can purchase it in as few as two steps&mdash;one
-to initiate the purchase and another to accept purchase details and permissions
-and complete the transaction.</p>
-
-<p>Google Play's convenient purchase experience is the same familiar process for
-all products everywhere across Google Play&mdash;apps, games, in-app products and
-subscriptions, and other digital content.</p>
-
-<h3 id="cloud-connected-purchase">Cloud-connected</h3>
-
-<p>Purchasing is even more convenient on Google Play because it’s
-cloud-connected. Users can find and purchase your products from anywhere&mdash;from
-their Android phones or using any web browser on any host computer. </p>
-
-<p>When users find an app or game they want to buy, they purchase it and download
-it instantly to their devices over-the-air. Users who sign in to the Google Play web site can also buy apps and games
-and push them instantly to their phones, tablets, or other devices. Google Play
-manages the application download.</p>
-
-<h3 id="payment-methods">Convenient payment options</h3>
-
-<p>Users can purchase your products on Google Play using several convenient
-payment methods&mdash;credit cards, Direct Carrier Billing, gift cards, and Google Play balance.</p>
-
-<p><span style="font-weight:500">Credit card</span> is the most common method of payment. Users can pay using any credit card
-that they’ve registered in Google Play. To make it easy for users to get started,
-registration is offered as a part of initial device setup process.</p>
-
-<div class="sidebox-wrapper" style="float:right;">
-<div class="sidebox">
-<h2>Payment methods on Google Play</h2>
-<ul>
-<li>Credit card</li>
-<li>Direct Carrier Billing</li>
-<li>Gift card</li>
-<li>Google Play balance (stored value)</li>
-</ul>
-</div>
-</div>
-
-<p>Subscribers on many popular carrier networks worldwide can charge purchases
-to their monthly mobile phone bills through <span style="font-weight:500">Direct
-Carrier Billing</span>. This form of payment is convenient and simple and is
-extremely popular in regions where credit cards are less common. More than 75
-million users in key markets around the world can purchase
-your products through Direct Carrier Billing. Many more will get the option in
-the months ahead.</p>
-
-<p><span style="font-weight:500">Google Play balance</span> is a stored account
-balance in Google Play. Users can increase their balance through promotions and
-offers in the store, and they can use their balanace to make purchases of apps,
-games, or other content. 
-
-<p>The payment methods available to users worldwide may vary, based on
-location, carrier network, and other factors.</p>
-
-<div style="float:left;margin-right:2em;margin-top:3em;margin-bottom:1em;width:220px;">
-<img src="{@docRoot}images/gp-subs.png" style="width:220px">
-</div>
-
-<h2 id="billing-models" style="margin-top:1.5em;">Choice of billing models</h2>
-
-<p>Google Play gives you a choice of billing models to let you monetize your
-products. </p>
-
-<p>You can offer apps to all users for free, or
-you can set an initial price for the app, paid before download. You can also
-sell one-time purchases and auto-renewing subscriptions from inside the app, and
-you can take advantage of AdMob integration to monetize your app through
-targeted advertising.</p>
-
-<div class="sidebox-wrapper">
-<div class="sidebox">
-<h2>Billing models on Google Play</h2>
-<ul>
-<li>Free (no charge to download)</li>
-<li>Priced (user charged before download)</li>
-<li>In-app products and subscriptions</li>
-</ul>
-</div>
-</div>
-
-<p>You can combine these billing models in different ways, based on your business
-needs or market conditions. </p>
-
-<p>For example, you can use a freemium or ad-supported model by distributing
-your app for free and selling in-app products or advertising. Alternatively you
-could set a nominal price for your app at download and sell value add-ons,
-gameplay levels, and upgrades as in-app products. The only restriction is that
-free apps must remain free (to download) for the life of the app.</p>
-
-<p>For details about in-app products or subscriptions,
-see <a href="{@docRoot}google/play/billing/index.html">Google Play In-app Billing</a>.</p>
-
-<h2 id="buyer-currency" style="margin-top:1.5em;">Flexible pricing in the currencies of your customers</h2>
-
-<div class="figure-right" style="width:250px;">
-<img src="{@docRoot}images/gp-buyer-currency.png" class="frame">
-</div>
-
-<p>Google Play gives you complete control over how you price your products. You
-can set prices in more than 130 countries, for millions of
-users around the world. When users browse your app’s product page or initiate a
-purchase, Google Play shows them the price they will be charged <em>in
-their local currency</em>.</p>
-
-<p>You can set and adjust your prices at any time, in any available currency. 
-Your prices in available currencies are independent, so you can adjust one
-price without affecting others. This gives you the ability to run
-short-term promotions and discounts in specific countries and more easily
-manage shifts in exchange rates.</p>
-
-<p>You can set and manage prices for your apps and in-app products from the
-Google Play Developer Console.</p>
-
-<h2 id="payouts">Monthly payouts in your local currency</h2>
-
-<p>To sell products in Google Play, all you have to do is register for a Google
-Wallet merchant account and link it to your Google Play Android Developer
-Console account (see <a
-href="{@docRoot}distribute/googleplay/publish/register.html">Get Started with
-Publishing</a> for details). Once you’ve set up your account and published your
-apps, Google Play makes monthly payouts of sales proceeds to your merchant
-account, in your local currency.</p>
-
-<h2 id="reporting">Detailed financial reporting</h2>
-
-<p>When you sell priced apps or in-app products on Google Play, you get a
-variety of financial reports to help you track and project sales, optimize your
-marketing campaigns, and support your customers.</p>
-
-<p>To help you keep up-to-date with the current activity, you can download daily
-reports summarizing recent purchases of your products. The reports include
-estimated sales amounts and include a variety of other data for each
-transaction.</p>
-
-<p>At the close of the month, you can download a complete sales report that
-gives you the final details of all transactions that closed in the month,
-including the payout amounts and other data. Additional financial reports are
-available in your Google Wallet merchant account.</p>
diff --git a/docs/html/distribute/googleplay/about/visibility.jd b/docs/html/distribute/googleplay/about/visibility.jd
deleted file mode 100644
index 18f60e9..0000000
--- a/docs/html/distribute/googleplay/about/visibility.jd
+++ /dev/null
@@ -1,246 +0,0 @@
-page.title=Visibility for Your Apps
-page.metaDescription=
-
-@jd:body
-    
-<div style="float:right;margin:0px 0px 24px 0px;">
-  <img src="{@docRoot}images/gp-tab.png" style="width:420px" alt="" />
-</div>
-
-<p>A billion downloads a month and growing. Get your apps in front of millions
-of users at Google's scale. </p>  
-
-
-<h2 id="reach">Worldwide reach, rapid growth</h2>
-
-<p>Google Play is the premier store for distributing Android apps. It’s
-preinstalled on more than 400 million devices worldwide, a number growing by
-more than a million every day. Android users have downloaded
-more than <strong style="text-wrap:none;">25 billion apps</strong> from Google
-Play, growing at a rate of more than 1.5 billion per month.</p>
-
-<p>When you publish on Google Play, you put your apps in front of Android's huge
-base of active customers, in more than 130 countries and territories across the
-world. </p>
-
-<p>Google Play is a central part of the Android experience. New users
-personalize their devices with apps, games, and other Google Play content.
-Existing users return regularly to see what's trending and new. Downloading new
-apps is extremely convenient and fast&mdash; Google Play pushes  apps to the
-user's devices instantly, over the air. No cable or sync is ever needed.</p>
-
-<div style="float:left;margin:0px 20px 0px 0px;width:374px;">
-<div  style="width:378px;padding:2px;">
-<img src="{@docRoot}images/gp-growth-downloads.png" style="width:600px;margin-bottom:0em;">
-</div>
-<p class="image-caption" style="padding:.5em"><span
-style="font-weight:500;">Growth in app consumption</span>: Users download more than
-1.5 billion apps from Google Play each month.</p>
-</div>
-
-<div>
-<p>Google Play is also a top destination for visitors from the web. Anyone
-with a browser can explore everything that Google Play has to offer from its <a
-href="http://play.google.com/store">web site</a>. Android users can even buy and
-install the apps they want and Google Play pushes them automatically to their
-devices over the air. </p>
-
-<p>The accessiblility and convenience of the Google Play web
-site give you new ways to drive traffic to your products from online ads, web
-search, cross-linking, and more.</p>
-</div>
-
-   <div style="clear:both;">
-<h2>Built for app discovery</h2>
-
-<p>Google Play is designed to connect users with great apps and games. It
-provides key channels to help your app get noticed and gain traction in the
-marketplace.</p>
-
-<h3 id="ratings">User ratings and reviews</h3>
-
-<p>When you develop a great app, Android users show their appreciation through
-ratings and reviews. They rate your app (out of 5 stars) after downloading it
-and can post a short description of their experience. When other users are
-considering your app, they look at the ratings and reviews as key benchmarks of
-the app’s quality. </p>
-
-   </div>
-
-<p>Your app’s rating is one of the most important factors influencing its
-ranking in the various lists and search results in Google Play. It's also one of
-the key signals that the editorial staff looks for, when curating apps and games
-for promotion in the store.</p>
-
-<div style="border:1px solid #DDD;padding:1px;margin-left:110px;width:504px;">
-<img src="{@docRoot}images/gp-rating-web.png" style="width:500px;padding:0;margin:0;">
-</div>
-
-<h3 id="category" stdle="padding-top:2em;">Category browsing</h3>
-
-<p>When you publish an app in Google Play, you pick the category in which you
-want users to find your app. More than 30 categories are available. Inside each
-category, apps are ranked based on a combination of ratings, reviews, downloads,
-country, and other factors. Many popular categories also start with a collection
-of featured apps selected by the Google Play editorial staff.</p>
-
-<div style="clear:both;margin-top:2em;margin-left:10%;width:560px;">
-<div style="clear:both;margin-top:2em;">
-<img src="{@docRoot}images/gpp-cat-feature280-puzzle.png" style="width:180px">
-<img src="{@docRoot}images/gpp-cat-feature280-photo.png" style="width:180px">
-<img src="{@docRoot}images/gpp-cat-feature280-sports.png" style="width:180px">
-</div>
-<p class="image-caption"><span style="font-weight:500;">Featuring in
-categories</span>: Most app and game categories include a featured list curated
-by the editorial team.</p>
-</div>
-
-<h3 id="search">Search</h3>
-
-<p>Search on Google Play lets users pinpoint an app or game quickly. Search uses
-powerful heuristics to suggest terms as the user types, and it offers direct
-links to apps as suggestions. In results, users find the most relevant, most
-popular apps at the top. </p>
-
-<div style="float:left;margin:12px 24px 0px 0px;">
-<img src="{@docRoot}images/gp-top-new-paid.png" style="width:250px">
-</div>
-
-<h3 id="top-charts" style="padding-top:1em">Top charts and lists</h3>
-
-<p>Top charts keep users in touch with what’s popular and trending with Android
-users, right from the Apps and Games home pages. The charts are generated
-several times each day based on recent download activity, keeping them fresh and
-allowing new apps to move upward in the charts. To make the charts as relevant
-as possible for users across the world, they are also country-specific in
-Google Play's most popular countries.</p>
-
-<p>As your apps get traction and build momentum in downloads and ratings,
-they’ll climb one or more of the top charts and gain even more exposure.</p>
-
-<div>
-<table style="width:440px">
-<tr>
-<td style="width:100px">Top Free</td><td>Free apps and games</td></tr>
-<td style="width:140px">Top Paid</td><td>Priced apps and games</td></tr>
-<td>Top New Free</td><td>Less than 30 days old</td></tr>
-<td>Top New Paid</td><td>Less than 30 days old</td></tr>
-<td>Top Grossing</td><td>Gross proceeds, free or priced</td></tr>
-<td>Best Selling</td><td>Popular priced games</td></tr>
-<td>Trending</td><td>New arrivals growing quickly in installs</td>
-</tr>
-</table>
-</div>
-
-<div style="clear:both">
-<h4 id="featured" style="padding-top:2.5em;">Featured, Staff Picks, Collections,
-and Badges</h4>
-
-
-<div style="float:right;margin-left:18px;">
-<img src="{@docRoot}images/gp-apps-home.png" style="width:180px">
-<img src="{@docRoot}images/gp-games-home.png" style="width:180px">
-</div>
-
-<p>The Google Play editorial team is dedicated to bringing the best apps to the
-attention of users and setting the tone for app quality throughout the store. 
-It constantly reviews apps from across Google Play to find
-not only the best-known apps and games, but also the “diamonds in the rough” that
-they want more people to see. </p>
-
-<p>When the team finds great apps and games, it uses the <em>Featured</em>,
-<em>Staff Picks</em>, and other collections to promote them to users.</p>
-
-<p>You can't nominate your app for featuring, but the team is always
-on the lookout for great apps through a number of signals and indicators. 
-If you build an app that users love and that looks great on Android devices,
-the editorial team will notice.</p>
-</div>
-
-<h4>Featured and Staff Picks</h4>
-
-<p>Each week the Google Play editorial staff selects a new set of apps to
-promote in its popular <em>Featured</em> and <em>Staff Picks</em> collections.
-</p>
-
-The <em>Featured</em> collections highlight the latest and greatest app and game
-titles available for Android. Category featuring highlights the best and most
-popular apps in the top categories.
-
-<em>Staff Picks</em> collects all recently featured apps and games on Google
-Play. To better reach tablet users, there’s a special <em>Staff Picks</em>
-collection that highlights the best apps for Android tablets.</p>
-
-<div style="float:left;margin-right:18px;">
-<img src="{@docRoot}images/gp-collectibles.png" stydle="width:180px">
-
-</div>
-
-<h4>App collections</h4>
-
-<p>From time to time the editorial staff puts together a collection of apps and
-games based on a theme or seasonal event. The collections are popular with
-customers because they are timely and relevant, and they provide a new way to
-showcase great Android apps to users.</p>
-
-<p>The editorial staff chooses apps for collection promotions in a similar way
-as for featuring&mdash;high-quality apps that show the best of Android on phones
-and tablets. For collections the staff also looks for apps that can make an
-interesting or unique contribution to the collection as a whole. </p>
-
-<h4><img style="margin-right:.25em;margin-bottom:.5em;"
-src="{@docRoot}images/editorschoice_ann.png"> EDITORS' CHOICE</h4>
-
-<p><em>Editors’ Choice</em> is a curated collection of apps that highlights some
-of the very best apps available on Android. These apps are chosen for high
-quality and great UI, long-term popularity, and innovative use of Android
-features.</p>
-
-<p>Apps chosen for <em>Editors’ Choice</em> also receive a badge that is
-displayed wherever the app name is seen in Google Play.</p>
-
-<h4><img style="margin-right:.25em;margin-bottom:.5em;"
-src="{@docRoot}images/topdev_ann.png"> TOP DEVELOPER</h4>
-
-<p>Top Developer is a badge recognizing established, respected developers for
-their commitment to launching high-quality and innovative apps on
-Android. The Google Play editorial staff selects developers awards a Top
-Developer badge from time to time, based on the cumulative work of the
-developer.</p>
-
-<p>The Top Developer badge appears next to the developer name wherever it is
-displayed in Google Play. For a developer, the badge means long-term recognition
-of all of your apps. For users, the badge signifies an additional level of trust
-and confidence in your products.</p>
-
-<h3 id="details">Rich, colorful product pages</h3>
-
-<p>In Google Play, your app’s storefront is its <em>product details page</em>
-&mdash; a rich and colorful page that lets you promote your app, highlight its
-ratings and reviews, and show what your app can do. 
-
-<p>Your product details page is the one page where your users come to find out
-everything about your app. When they see your app listed in search results, top
-charts, category listings, and collections, one tap takes them directly to your 
-product details page.</p>
-
-<div style="float:right;margin-left:10px;">
-<img src="{@docRoot}images/gp-details-pages-magicpiano.png" style="width:500px">
-</div>
-
-<p>You can manage your product details page through the <span
-style="font-weight:500">Google Play Android Develeper Console</span>, from any
-web browser. Just sign in, upload or update your brand assets, and enter your
-product details in the languages of your markets. </p>
-
-<p>When you publish, Google Play adds your app’s ratings, reviews, links to your
-other products, and more, and makes sure your product details page looks great
-on phones, tablets, or in a web browser.</p>
-
-<p>You can link web users directly to your product details page from outside
-Google Play, such as from your web site, an ad campaign, reviews, social media
-posts, and more. See <a href="{@docRoot}distribute/googleplay/promote/linking.html">Linking
-to Your Products</a> to find out how. </p>
-
-<p>To learn more about how to create your product details page, see
-<a href="{@docRoot}distribute/googleplay/publish/index.html">Publishing on Google Play</a>.</p>
diff --git a/docs/html/distribute/googleplay/developer-console.jd b/docs/html/distribute/googleplay/developer-console.jd
new file mode 100644
index 0000000..6263431
--- /dev/null
+++ b/docs/html/distribute/googleplay/developer-console.jd
@@ -0,0 +1,600 @@
+page.title=Developer Console
+page.metaDescription=Learn about the Developer Console, your home for app publishing on Google Play.
+page.image=/distribute/images/developer-console.jpg
+Xnonavpage=true
+
+@jd:body
+    
+    <div id="qv-wrapper">           
+  <div id="qv">
+    <h2>Publishing Features</h2>
+    <ol>
+      <li><a href="#allapps">All Applications</a></li>
+      <li><a href="#account-details">Your Account Details</a></li>
+      <li><a href="#merchant-account">Linking Your Merchant Account</a></li>
+      <li><a href="#multiple-user-accounts">Multiple User Accounts</a></li>
+      <li><a href="#alpha-beta">Alpha and Beta Testing</a></li>
+      <li><a href="#staged-rollouts">Staged Rollouts</a></li>
+      <li><a href="#multiple-apk">Multiple APK Support</a></li>
+      <li><a href="#selling-pricing-your-products">Selling and Pricing</a></li>
+      <li><a href="#in-app-products">In-App Products</a></li>
+      <li><a href="#distribution-controls">Distribution Controls</a></li>
+      <li><a href="#reviews-reports">User Reviews, Crash Reports</a></li>
+      <li><a href="#app-stats">App Stats</a></li>
+      <li><a href="#related-resources">Related Resources</a></li>
+    </ol>
+  </div>
+</div>
+
+<p>
+  The <a href="https://play.google.com/apps/publish/">Google Play Developer
+  Console</a> is your home for publishing operations and tools.
+</p>
+<!-- <img src="{@docRoot}images/gp-dc-startscreen.jpg" style="width:480px;" /> -->
+<img src="{@docRoot}images/gp-devconsole-home.png" style="width:480px;">
+<p>
+  Upload apps, build your product pages, configure prices and distribution, and
+  publish. You can manage all phases of publishing on Google Play through the
+  Developer Console, from any web browser.
+</p>
+
+<p>
+  Once you've <a href=
+  "{@docRoot}distribute/googleplay/start.html">registered</a> and received
+  verification by email, you can sign in to your Google Play Developer Console.
+</p>
+
+<div class="headerLine clearfloat">
+  <h1 id="allapps">
+    All Applications
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  Start in All Applications, which gives you a quick overview of your apps,
+  lets you jump to stats, reviews, and product details, or upload a new app.
+</p>
+
+<div style="padding:1em 0em 0em 0em;">
+  <img src="{@docRoot}images/gp-dc-home.png" class="border-img">
+</div>
+
+<div class="headerLine clearfloat" style="margin-top:-6px">
+  <h1 id="account-details">
+    Your Account Details
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  Specify basic developer profile information about yourself or your company on
+  the accounts detail page. This identifies you to Google Play and your
+  customers. You can go back at any time to edit the information and change
+  your settings.
+</p>
+
+<div>
+  <img src="{@docRoot}images/gp-dc-profile.png" class="frame">
+</div>
+
+<p>
+  Your developer profile contains:
+</p>
+
+<ul>
+  <li>
+    <p>
+      Developer name &mdash; displayed on your store listing page and elsewhere
+      on Google Play.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Contact information &mdash; used by Google only, it isn't seen by your
+      customers.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Web site URL &mdash; displayed on your store listing page.
+    </p>
+  </li>
+</ul>
+
+<p>
+  On the account details page you can also add restricted access for marketers
+  and other teams, register for a merchant account, or set up test accounts for
+  Google Play licensing.
+</p>
+
+<div class="headerLine clearfloat">
+  <h1 id="merchant-account">
+    Linking Your Merchant Account
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  If you want to sell apps or in-app products, link your Google Wallet Merchant
+  Account to your developer profile. Google Play uses the linked merchant
+  account for financial and tax identification, as well as for monthly payouts
+  from sales.
+</p>
+
+<div class="headerLine clearfloat">
+  <h1 id="multiple-user-accounts">
+    Multiple User Accounts
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  Set up user accounts for other team members to access different parts of your
+  Developer Console.
+</p>
+
+<div style="width:550px;">
+  <img src="{@docRoot}images/gp-dc-invite.png" class="frame">
+</div>
+
+<p>
+  The first account registered is the <em>account owner</em>, with full access
+  to all parts of the console. The owner can add <em>user accounts</em> and
+  manage console access.
+</p>
+
+<p>
+  For example, an owner can grant users access to publishing and app
+  configuration, but not to financial reports. Learn how to <a href=
+  "https://support.google.com/googleplay/android-developer/answer/2528691">set
+  up multiple accounts</a> now.
+</p>
+
+<div class="headerLine clearfloat">
+  <h1 id="store-listing-details">
+    Store Listing Details
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  Use the Developer Console to set up a <em>Store Listing page</em>. This is
+  the home for your app in Google Play. It's the page users see on their mobile
+  phones or on the web to learn about your app and download it.
+</p>
+
+<p>
+  Upload custom brand assets, screenshots, and videos to highlight what's great
+  about your app. Provide a localized description, add notes about the latest
+  version, and more. You can update your store listing at any time.
+</p>
+
+<div>
+  <img src="{@docRoot}images/gp-dc-details.png" class="frame">
+</div>
+
+<div class="headerLine clearfloat">
+  <h1 id="upload-instantly-publish">
+    Upload and Instantly Publish
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  From the Developer Console you can quickly upload and publish a release-ready
+  Android application package file. The app is a <em>draft</em> until you
+  publish it, at which time Google Play makes your store listing page and app
+  available to users&mdash;your app appears in the store listings within hours,
+  not weeks.
+</p>
+
+<p>
+  Once your app is published, you can update it as often as you want: Change
+  prices, configuration, and distribution options at any time, without needing
+  to update your app binary.
+</p>
+
+<p>
+  As you add features or address code issues, you can publish an updated binary
+  at any time. The new version is available almost immediately and existing
+  customers are notified that an update is ready for download. Users can also
+  accept automatic updates to your app, so that your updates are delivered and
+  installed as soon as you publish them. You can unpublish your apps app at any
+  time.
+</p>
+
+<div class="headerLine clearfloat">
+  <h1 id="alpha-beta">
+    Alpha and Beta Testing
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  It's always valuable to get real-world feedback from users, especially before
+  launch. Google Play makes it easy to distribute pre-release versions of your
+  app to alpha and beta test groups anywhere in the world.
+</p>
+
+<p>
+  In the <strong>APK</strong> section of your Google Play Developer Console
+  you’ll find the <strong>Alpha Testing</strong> and <strong>Beta
+  Testing</strong> tabs. Here you can upload versions of your apps’ APK files
+  and define a list of testers as a <a href=
+  "https://support.google.com/groups/answer/46601">Google Group</a> or <a href=
+  "https://support.google.com/plus/topic/2888488">Google+ Community</a>. Once
+  this is done you’ll receive a URL that you forward to your testers, from
+  which they can opt-in to the testing program.
+</p>
+
+<div>
+  <img src="{@docRoot}images/gp-dc-ab.png" class="frame">
+</div>
+
+<p>
+  After opting-in, your testers then go to your app’s product page and when
+  they download the app Google Play will deliver them the alpha or beta version
+  as appropriate. Incidentally, if a user happens to be opted-in to both your
+  testing groups, Google Play will always deliver them the alpha test version.
+</p>
+
+<p>
+  Note that users cannot provide feedback and reviews on alpha and beta
+  versions of your apps. To gather feedback you could used the <a href=
+  "https://support.google.com/groups/answer/46601">Google Group</a> or <a href=
+  "https://support.google.com/plus/topic/2888488">Google+ Community</a>, or
+  setup an email address or your own website.
+</p>
+
+<p>
+  You can use these testing programs to <a href=
+  "{@docRoot}distribute/essentials/optimizing-your-app.html">optimize your
+  apps</a>, help with <a href=
+  "{@docRoot}distribute/users/expand-to-new-markets.html">rollout to new
+  markets</a>, and start <a href=
+  "{@docRoot}distribute/users/build-community.html">building your
+  community</a>. There is also more information on using beta test in the
+  <a href="{@docRoot}distribute/tools/launch-checklist.html">Launch
+  Checklist</a> and <a href=
+  "{@docRoot}distribute/tools/localization-checklist.html">Localization
+  Checklist</a>.
+</p>
+
+<div class="headerLine clearfloat">
+  <h1 id="staged-rollouts">
+    Staged Rollouts
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  You can also stage the rollout of your apps using the Production tab in the
+  APK section of your Google Play Developer Console. Here you can define the
+  percentage of user who’ll be able to download your app.
+</p>
+
+<p>
+  Staging your rollout will help limit the impact of unexpected bugs or server
+  load and enable you to gauge user feedback with an unbiased sample of users.
+  Users can rate and review your apps during staged roll outs, so if you’re
+  hesitant, start your rollout to a small percentage of users. Be sure to watch
+  for and respond to any negative reviews.
+</p>
+
+<p>
+  Note that rollbacks aren’t supported due to the <a href=
+  "{@docRoot}tools/publishing/versioning.html">app versioning requirements</a>
+  of the Android platform. If you need to rollback, consider launching a
+  previous APK with a new version number. However, this practice should be used
+  only as a last resort, as users will lose access to new features and your old
+  app may not be forward-compatible with your server changes or data formats,
+  so be sure to run <a href="#alpha-beta">alpha and beta tests</a> of your
+  updates.
+</p>
+
+<div class="headerLine clearfloat">
+  <h1 id="multiple-apk">
+    Multiple APK Support
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  In most cases, a single app package (APK) is all you need, and it’s usually
+  the easiest way to manage and maintain the app. However, if you need to
+  deliver a different APK to different devices, Google Play provides a way to
+  do that.
+</p>
+
+<p>
+  <em>Multiple APK support</em> lets you create multiple app packages that use
+  the same package name but differ in their OpenGL texture compression formats,
+  screen-size support, or Android platform versions supported. You can simply
+  upload all the APKs under a single product listing and Google Play selects
+  the best ones to deliver to users, based on the characteristics of their
+  devices.
+</p>
+
+<p>
+  You can also upload up to two secondary downloads for each published APK,
+  including multiple APKs, using the <em>APK Expansion Files</em> option. Each
+  expansion file can be up to 2GB and contain any type of code or assets.
+  Google Play hosts them for free and handles the download of the files as part
+  of the normal app installation.
+</p>
+
+<div class="headerLine clearfloat">
+  <h1 id="selling-pricing-your-products">
+    Selling and Pricing Your Products
+  </h1>
+
+  <hr>
+</div>
+
+<div class="figure-right">
+  <img src="{@docRoot}images/gp-buyer-currency.png" class="frame">
+</div>
+
+<p>
+  You have tools to set prices for your apps and in-app products. Your app can
+  be free to download or priced, requiring payment before download.
+</p>
+
+<ul>
+  <li>If you publish your app as free, it must <strong>remain free for the life
+  of the app</strong>. Free apps can be downloaded by all users in Google Play.
+  </li>
+
+  <li>If you publish it as priced, you can later change it to free. Priced apps
+  can be purchased and downloaded only by users who have registered a form of
+  payment in Google Play.
+  </li>
+</ul>
+
+<div class="sidebox-wrapper" style="float:right;">
+  <div class="sidebox">
+    <p>
+      See <a href=
+      "http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&amp;answer=138294&amp;topic=2365624&amp;ctx=topic">
+      Supported locations for distributing applications</a> for a list of
+      countries where you can distribute or sell your apps.
+    </p>
+  </div>
+</div>
+
+<p>
+  You can also offer in-app products and subscriptions, whether the app is free
+  or priced. Set prices separately for priced apps, in-app products, and
+  subscriptions.
+</p>
+
+<p>
+  When users browse your app product pages or initiate a purchase, Google Play
+  shows them the price they’ll be charged in their local currency.
+</p>
+
+<p>
+  For each product, you initially set a default price in your own currency. If
+  you do no more, Google Play will automatically set local prices once a month
+  based on the US-Dollar price for your app.
+</p>
+
+<p>
+  However, Google Play gives you complete control over how you price your
+  products in each country. To start you can manually set fixed local prices
+  from the default price, using the <strong>auto-convert prices now</strong>
+  feature. You can then review these prices and set new ones for any countries
+  you wish &mdash; the price for each country is independent, so you can adjust
+  one price without affecting others. For most countries, the price you set is
+  the final price charged to users, including taxes.
+</p>
+
+<p>
+  For more on pricing your apps, see <a href=
+  "{@docRoot}distribute/users/expand-to-new-markets.html#localize-your-google-play-listing">
+  Expand into New Markets</a>.
+</p>
+
+<div class="headerLine clearfloat">
+  <h1 id="in-app-products">
+    In-app Products
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  You can sell in-app products and subscriptions using <a href=
+  "{@docRoot}google/play/billing/index.html">Google Play In-app Billing</a> as
+  a way to monetize your apps. In-app products are one-time purchases, while
+  subscriptions are recurring charges on a monthly or annual basis.
+</p>
+
+<p>
+  In the <strong>In-app Products</strong> section for a specific published or
+  draft APK you:
+</p>
+
+<ul>
+  <li>Create product lists for in-app products and subscriptions.
+  </li>
+
+  <li>Set prices.
+  </li>
+
+  <li>Publish the products with the app or withdraw obsolete products.
+  </li>
+</ul>
+
+<p>
+  For details on how to implement In-app Billing, see the <a href=
+  "{@docRoot}google/play/billing/index.html">In-app Billing</a> developer
+  documentation. You make use of in-app products in the <a href=
+  "{@docRoot}distribute/monetize/premium.html">Premium</a>, <a href=
+  "{@docRoot}distribute/monetize/freemium.html">Freemium</a>, and <a href=
+  "{@docRoot}distribute/monetize/subscriptions.html">Subscription</a>
+  monetization models
+</p>
+
+<div class="headerLine clearfloat">
+  <h1 id="distribution-controls">
+    Distribution Controls
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  Manage which countries and territories your apps will distribute to. For some
+  countries, you can choose which carriers you want to target. You can also see
+  the list of devices your app is available for, based on any distribution
+  rules declared in its manifest file.
+</p>
+
+<h3 id="geotargeting">
+  Geographic targeting
+</h3>
+
+<p>
+  You can use controls in the Google Play Developer Console to easily manage
+  the geographic distribution of your apps, without any changes in your
+  application binary. You can specify which countries and territories you want
+  to distribute to, and even which carriers (for some countries).
+</p>
+
+<p>
+  When users visit the store, Google Play makes sure that they are in one of
+  your targeted countries before downloading your app. You can change your
+  country and carrier targeting at any time just by saving changes in the
+  Google Play Developer Console.
+</p>
+
+<div class="figure-right" style="width:500px;">
+  <img src="{@docRoot}images/gp-supported-dev-requirements.png" class="frame">
+</div>
+
+<p>
+  To help you market to users around the world, you can <a href=
+  "{@docRoot}distribute/tools/launch-checklist.html#start-localization">localize
+  your store listing</a>, including app details and description, promotional
+  graphics, screenshots, and more.
+</p>
+
+<h3 id="captargeting">
+  Capabilities targeting
+</h3>
+
+<p>
+  Google Play also lets you control distribution according to device features
+  or capabilities that your app depends on. There are several types of
+  dependencies that the app can define in its manifest, such as hardware
+  features, OpenGL texture compression formats, libraries, Android platform
+  versions, and others.
+</p>
+
+<p>
+  When you upload your app, Google Play reads the dependencies and sets up any
+  necessary distribution rules. For technical information about declaring
+  dependencies, read <a href="{@docRoot}google/play/filters.html">Filters on
+  Google Play</a>.
+</p>
+
+<p>
+  For pinpoint control over distribution, Google Play lets you see all of the
+  devices your app is available to based on its dependencies (if any). From the
+  Google Play Developer Console, you can list the supported devices and even
+  exclude specific devices if needed.
+</p>
+
+<div class="headerLine clearfloat">
+  <h1 id="reviews-reports">
+    User Reviews and Crash Reports
+  </h1>
+
+  <hr>
+</div>
+
+<div class="figure-right" style="width:500px;">
+  <img src="{@docRoot}images/gp-dc-reviews.png" class="frame">
+  <p class="img-caption">
+    The User reviews section gives you access to user reviews for a specific
+    app. You can filter reviews in a number of ways to locate issues more
+    easily and support your customers more effectively.
+  </p>
+</div>
+
+<p>
+  Google Play makes it easy for users to submit reviews of your app for the
+  benefit of other users. The reviews give you usability feedback, support
+  requests, and details of important functionality issues direct from your
+  customers.
+</p>
+
+<p>
+  Use crash reports for debugging and improving your app. You can see crash
+  reports with stack trace and other data, submitted automatically from Android
+  devices.
+</p>
+
+<div class="headerLine clearfloat">
+  <h1 id="app-stats">
+    App Statistics
+  </h1>
+
+  <hr>
+</div>
+
+<div class="figure" style="width:500px">
+  <img src="{@docRoot}images/gp-dc-stats.png">
+  <p class="img-caption">
+    <b>App statistics page</b>: Shows you a variety of statistics about a
+    specific app's installation performance.
+  </p>
+</div>
+
+<p>
+  You get detailed statistics on the install performance of your app.
+</p>
+
+<p>
+  See installation metrics measured by unique users as well as by unique
+  devices. View active installs, total installs, upgrades, daily installs and
+  uninstalls, and metrics about ratings.
+</p>
+
+<p>
+  Zoom into the installation numbers by metric, including Android platform
+  version, device, country, language, app version, and carrier. View the
+  installation data for each dimension on timeline charts.
+</p>
+
+<p>
+  These charts highlight your app’s installation peaks and longer-term trends.
+  They help you learn your user’s adoption behavior, correlate statistics to
+  promotions, see the effect of app improvements, and other factors. Focus in
+  on data inside a dimension by adding specific points to the timeline.
+</p>
+
+<div class="dynamic-grid">
+<div class="headerLine clearfloat">
+<h1 id="related-resources">Related Resources</h1><hr/>
+</div>
+
+<div class="resource-widget resource-flow-layout col-13"
+  data-query="collection:distribute/googleplay/developerconsole"
+  data-sortOrder="-timestamp"
+  data-cardSizes="9x3"
+  data-maxResults="6"></div>
+  </div>
\ No newline at end of file
diff --git a/docs/html/distribute/googleplay/edu/about.jd b/docs/html/distribute/googleplay/edu/about.jd
index 20a0d4d..3944909 100644
--- a/docs/html/distribute/googleplay/edu/about.jd
+++ b/docs/html/distribute/googleplay/edu/about.jd
@@ -1,103 +1,131 @@
-page.title=About Google Play for Education
-page.metaDescription=How Google Play for Education helps you reach a new audience of educators.
-excludeFromSuggestions=true
+page.title=Google Play for Education
+page.image=/distribute/images/about-play-education.jpg
+page.metaDescription=Distribute your educational app directly to educators and schools.
+meta.tags="gpfe, googleplay, distribution, edu"
+page.tags="education"
+Xnonavpage=true
+
 @jd:body
 
-    <div style="position:absolute;margin-left: 636px;
-            margin-top:-76px;color:#777;">If you're interested<br>
-            <a href="{@docRoot}distribute/googleplay/edu/contact.html"
-            class="go-link"
-            style="display: block;text-align: right;">SIGN UP</a></div>
+<p>
+  Google Play for Education is an extension of Google Play designed for
+  schools. Here educators can discover apps approved by teachers for teachers,
+  as well as educational videos and a collection of classic books for their
+  classroom.
+</p>
 
-    <div style="float:right;margin:0px 0px 24px 44px;">
-  <img src="{@docRoot}images/gp-edu-apps-n7.jpg" style="width:420px" alt="" />
-</div>
+<p>
+  Teachers can search for approved apps by grade, subject and standard,
+  including Common Core State Standards. They can bulk purchase and pay using a
+  purchase order, then instant distribution let educators bring your apps
+  directly to classrooms and schools.
+</p>
 
-<p>Introducing Google Play for Education, the online destination where schools
-can find the right tablet content and tools for their students and teachers.</p>
 
-<p>With easy bulk ordering for groups, schools can purchase and
-instantly distribute your apps, and videos right to their students’
-devices.</p>
+<div class="resource-widget resource-flow-layout col-13"
+  data-query="collection:distribute/googleplay/gpfe/highlight"
+  data-sortOrder="-timestamp"
+  data-cardSizes="18x6,"
+  data-maxResults="1"></div>
 
-<p>Google Play for Education can help your innovative educational apps
-gain visibility with the right audiences, without having to knock on school doors. </p>
 
-<p><a class="landing-page-link" style="text-align:right;" href="#video">Watch a Video</a></p>
+<!-- <div class="center-img"><img src="{@docRoot}images/gp-edu-hero14.jpg" class="" /></div> -->
 
-<div class="landing-docs">
-  <div class="col-6 normal-links">
-    <h3 style="clear:left">For Developers</h3>
+<p>
+  If you have an educational app, include it in Google Play for Education.
+  Google Play for Education can help your innovative educational apps gain
+  visibility with the right audiences, without having to knock on school doors.
+</p>
 
-<h4>Get discovered</h4>
+<div style="margin:30px 0 20px 0;" class="clearfloat dynamic-grid">
+  <div style="width:48%; margin-right:2%; float:left;">
+    <div class="centered-full-image">
+      <img src="{@docRoot}images/gpfe-developer.png">
+    </div>
 
-<p>With Google Play for Education, teachers and administrators can
-browse content by curriculum, grade, and standard &mdash; discovering the right
-content for their students. If your app offers an exciting new
-way to learn sixth grade algebra, math educators will be able to find,
-purchase, and distribute your app to their classes in a few clicks.</p>
-
-<h4>Reach more schools and students</h4>
-
-<p>Over 30 million students, faculty, and staff are already using
-Google Apps for Education and other Google services. Many of these schools are
-excited to take advantage of tablets with Google Play for Education and they
-look to bringing your apps into their classrooms,
-especially apps using Google sign-on.</p>
-
-<h4>Monetize effectively</h4>
-<p>With Google Play for Education, educators are able to make high-volume purchases
-using standard institutional payment mechanisms and distribute them to the students
-they want &mdash; whether it is a class of 20 or a district of 20,000.</p>
-<code></code>
+    <h3>
+      FOR DEVELOPERS
+    </h3>
+    <b>Get discovered</b>
+    <p>
+      With Google Play for Education, teachers and administrators can browse
+      content by curriculum, grade, and standard &mdash; discovering the right
+      content for their students. If your app offers an exciting new way to
+      learn sixth grade algebra, math educators will be able to find, purchase,
+      and distribute your app to their classes in a few clicks.
+    </p>
+    <b>Reach more schools and students</b>
+    <p>
+      Millions of students, faculty, and staff are using Google Apps for
+      Education and other Google services. Many of these schools are excited to
+      take advantage of tablets with Google Play for Education and they are
+      looking to bring your apps into their classrooms, especially apps using
+      Google sign-on.
+    </p>
+    <b>Monetize effectively</b>
+    <p>
+      With Google Play for Education, educators are able to make high-volume
+      purchases using standard institutional payment mechanisms and then
+      distribute apps to the students who need them — whether it’s a class of
+      20 or a district of 20,000.
+    </p>
   </div>
 
-  <div class="col-6 normal-links">
-    <h3 style="clear:left">For Educators</h3>
-    <h4>Android tablets in the classroom</h4>
-    <p>Google Play for Education brings the innovation of Android technology
-into classrooms. School districts can set up and deploy large numbers of devices in
-just minutes or hours rather than days.</p>
+  <div style="width:48%; margin-left:2%; float:left;">
+    <div class="centered-full-image">
+      <img src="{@docRoot}images/gpfe-educator.png">
+    </div>
 
-    <h4>Curriculum-based discovery</h4>
-    <p>Powerful browsing tools let educators quickly discover apps,
-videos, and other content&mdash;with many recommended by teachers and
-categorized according to familiar Core Curriculum standards.  
-
-    <h4>Bulk purchase with institutional payment</h4>
-    <p>Convenient purchasing and delivery tools let educators buy apps in bulk
-using purchase orders and other payment methods that are easy for schools to
-manage.</p>
-
-    <h4>Over-the-air delivery to student devices</h4>
-
-      <p>After finding apps they want to use, educators can push them instantly
-to student devices over the air. They can send the apps to individuals or groups
-of any size, across classrooms, schools, or even districts. </p>
-
+    <h3>
+      FOR EDUCATORS
+    </h3>
+    <b>Android tablets in the classroom</b>
+    <p>
+      Google Play for Education brings the innovation of Android technology
+      into classrooms. School districts can set up and deploy large numbers of
+      devices in just minutes or hours, rather than days.
+    </p>
+    <b>Curriculum-based discovery</b>
+    <p>
+      Powerful browsing tools let educators quickly discover apps, videos, and
+      other content—with many recommended by teachers and categorized according
+      to familiar Core Curriculum standards.
+    </p>
+    <b>Bulk purchase with institutional payment</b>
+    <p>
+      Convenient purchasing and delivery tools let educators buy apps in bulk,
+      using purchase orders and other payment methods that are easy for schools
+      to manage.
+    </p>
+    <b>Over-the-air delivery to student devices</b>
+    <p>
+      After finding apps they want, educators can push them instantly to
+      student devices over the air. They can send the apps to individuals or
+      groups of any size, across classrooms, schools, or even districts.
+    </p>
   </div>
-
-
 </div>
-<div id="video" style="background: #F0F0F0;
-            border-top: 1px solid #DDD;
-            padding: 0px 0 24px 0;
-            overflow: auto;
-            clear:both;
-            margin-bottom:40px;
-            margin-top:30px;">
-   <div style="padding:0 0 0 29px;">
-        <h4>Introducing Google Play for Education</h4>
 
-          <div style="width:700px;">
-          <p style="margin-top:26px;
-                    margin-bottom:12px;">
-          Hear how Google Play for Education works and how developers can leverage the unique business opportunities in creating educational apps for the K-12 market. There's a demo at 4m10s.</p>
-           </div>
-           <iframe style="float:left;
-             margin-right:24px;
-             margin-top:14px;" width="700" height="394" src=
-             "http://www.youtube.com/embed/haEmsMo0f3w?HD=1;rel=0;origin=developer.android.com;" frameborder="0" allowfullscreen>
-           </iframe>
-   </div> 
+<div class="headerLine clearfloat">
+<h1>Related Resources</h1><hr>
 </div>
+
+<div class="dynamic-grid">
+
+<h3>For Developers</h3>
+
+<div class="resource-widget resource-flow-layout col-13"
+    data-query="collection:distribute/googleplay/gpfe/dev/about"
+    data-sortOrder="-timestamp"
+    data-cardSizes="9x3"
+    data-maxResults="6"></div>
+
+<h3>For Teachers and Educators</h3>
+
+<div class="resource-widget resource-flow-layout col-13"
+    data-query="collection:distribute/googleplay/aboutgpfe/educators/about"
+    data-sortOrder="-timestamp"
+    data-cardSizes="9x3"
+    data-maxResults="3"></div>
+
+</div>
\ No newline at end of file
diff --git a/docs/html/distribute/googleplay/edu/contact.jd b/docs/html/distribute/googleplay/edu/contact.jd
index ca83438..042a92b 100644
--- a/docs/html/distribute/googleplay/edu/contact.jd
+++ b/docs/html/distribute/googleplay/edu/contact.jd
@@ -7,32 +7,29 @@
 bring your first-class educational content into schools across the United
 States, and to a broader international audience in the future. </p>
 
-<div class="vspace size-1">
-  &nbsp;
-</div>
 
-<div class="layout-content-row">
-  <div class="layout-content-col span-6">
-    <h4>
-      For Developers
-    </h4>
-    <p>
+<div style="margin:0 0 20px 0;" class="clearfloat dynamic-grid">
+  <div style="width:48%; margin-right:2%; float:left;">
+
+    <h3>
+      FOR DEVELOPERS
+    </h3>
+ <p>
 Whether you have an existing educational app or are developing a fresh idea that
 will unlock learning in the classroom &mdash; sign up to receive information about
-the upcoming launch of Google Play for Education. To get your apps ready, read our
-<a href="{@docRoot}distribute/googleplay/edu/guidelines.html">guidelines</a> for building
-educational apps.</p>
-    </p><a href="http://developer.android.com/edu/signup">Developer Sign Up »</a>
+Google Play for Education. To get your apps ready, read our
+<a href="{@docRoot}distribute/essentials/gpfe-guidelines.html">guidelines for building
+educational apps</a>.</p>
+    </p><a href="http://developer.android.com/edu/signup">Developer Sign Up »</a>    </p>
   </div>
-  <div class="layout-content-col span-6">
-    <h4>
-      For Educators
-    </h4>
-    <p>
+
+  <div style="width:48%; margin-left:2%; float:left;">
+
+    <h3>
+      FOR EDUCATORS
+    </h3>
+     <p>
 If you're a school or system interested in tablets and Google Play for Education,
 complete the expression of interest form at <a href="http://www.google.com/edu/android">www.google.com/edu/android</a>.
-  </p><a href="http://www.google.com/edu/android">School Interest Form »</a>
-  </div>
-</div>
-
-
+  </p><a href="http://www.google.com/edu/android">School Interest Form »</a>  </div>
+</div>
\ No newline at end of file
diff --git a/docs/html/distribute/googleplay/edu/faq.jd b/docs/html/distribute/googleplay/edu/faq.jd
index 0c3b185..0866da5 100644
--- a/docs/html/distribute/googleplay/edu/faq.jd
+++ b/docs/html/distribute/googleplay/edu/faq.jd
@@ -1,372 +1,433 @@
-page.title=Google Play for Education FAQ
-page.metaDescription=Questions and answers about Google Play for Education.
-excludeFromSuggestions=true
+page.title=Education FAQ
+meta.tags="gpfe, edu"
+page.metaDescription=Answers to frequent questions about Google Play for Education.
+page.image=/distribute/images/gpfe-faq.jpg
+
 @jd:body
 
-     <div style="position:absolute;margin-left: 636px;
-            margin-top:-76px;color:#777;">If you're interested<br>
-            <a href="{@docRoot}distribute/googleplay/edu/contact.html"
-            class="go-link"
-            style="display: block;text-align: right;">SIGN UP</a></div>
-    
- 
-    <style>
-  dt {
-    font-weight:bold;
-  }
-  </style>
-  
 <div id="qv-wrapper">
-<ol id="qv">
-<h2>In this document</h2>
-<ol>
-  <li><a href="#business">Business Model</a></li>
-  <li><a href="#free_trials">Free Trials</a></li>
-  <li><a href="#discovery">Discovery</a></li>
-  <li><a href="#reviews">App Review Process</a></li>
-  <li><a href="#features">App Features</a></li>
-  <li><a href="#marketing">Marketing and ROI</a></li>
-  <li><a href="#devices">Devices</a></li>
-  <li><a href="#accounts">Accounts</a></li>
-</ol>
+  <div id="qv">
+  <h2>
+    Topics
+  </h2>
+
+  <ol>
+    <li>
+    <a href="#business-model-and-monetization">Business Model and
+    Monetization</a>
+    </li>
+
+    <li>
+    <a href="#free-trials">Free Trials</a>
+    </li>
+
+    <li>
+    <a href="#discovery">Discovery</a>
+    </li>
+
+    <li>
+    <a href="#app-review-process">App Review Process</a>
+    </li>
+
+    <li>
+    <a href="#app-features">App Features</a>
+    </li>
+
+    <li>
+    <a href="#marketing-and-roi">Marketing and ROI</a>
+    </li>
+
+    <li>
+    <a href="#devices">Devices</a>
+    </li>
+
+    <li>
+    <a href="#accounts">Accounts</a>
+    </li>
+
+    <li>
+    <a href="#related-resources">Related Resources</a>
+    </li>
+  </ol>
+  </div>
 </div>
 
 <p>
-  The sections below provide more information about Google Play for Education
-  and answer common questions that you might have about it.
+  This page provides answers to common questions that you might have about
+  Google Play for Education.
 </p>
 
+<div class="headerLine">
+  <h1 id="business-model-and-monetization">
+  Business Model and Monetization
+  </h1>
 
-<h2 id="business">Business Model and Monetization</h2>
+  <hr>
+</div>
 
-<dl>
-  <dt>
-    What is Google Play for Education?
-  </dt>
+<p>
+  <strong>What is Google Play for Education?</strong>
+</p>
 
-  <dd>
-    Google Play for Education is a new online destination designed for schools.
-    Teachers can discover educational apps, books, and videos to meet the needs
-    of a single student, a classroom, or a whole district. Educators can browse
-    apps by grade, subject, keyword, or standard including common core.
-    Purchasing is done via PO with no credit card required. Apps are
-    distributed to tablets instantly via the cloud.
-  </dd>
+<p>
+  Google Play for Education is a new online destination designed for schools.
+  Teachers can discover educational apps, books, and videos to meet the needs
+  of a single student, a classroom, or a whole district. Educators can browse
+  apps by grade, subject, keyword, or standard including Common Core State
+  Standards. Purchasing is done using a PO with no credit card required. Apps
+  are distributed to tablets instantly through the cloud.
+</p>
 
-  <dt>
-    Is Google Play for Education primarily for students or educators?
-  </dt>
+<p>
+  <strong>Is Google Play for Education primarily for students or
+  educators?</strong>
+</p>
 
-  <dd>
-    The store on Google Play for Education is for educators, but its content is
-    for both educators and students. Teachers and administrators have the
-    ability to make purchases and control who within their school has access to
-    the purchase flows.
-  </dd>
+<p>
+  The store on Google Play for Education is for educators, but its content is
+  for both educators and students. Teachers and administrators have the ability
+  to make purchases and control who within their school has access to the
+  purchase flows.
+</p>
 
-  <dt>
-    Will Google Play for Education support subscription purchases?
-  </dt>
+<div class="figure">
+  <img src="{@docRoot}distribute/images/gpfe-faq.jpg" style=
+  "width:480px;margin:1em 0em 1.5em 1.5em;">
+</div>
 
-  <dd>
-    Currently, Google Play for Education supports one-time purchases. We are
-    investigating additional purchase mechanisms to enable more flexible
-    pricing models for developers and schools.
-  </dd>
+<p>
+  <strong>Will Google Play for Education support subscription
+  purchases?</strong>
+</p>
 
-  <dt>
-    Why is it recommended to disable in-app purchases?
-  </dt>
+<p>
+  Currently, Google Play for Education supports one-time purchases. We’re
+  investigating additional purchase mechanisms to enable more flexible pricing
+  models for developers and schools.
+</p>
 
-  <dd>
-    In-app purchase is currently not supported with Google Play for Education,
-    and a student device will block the Play transaction if a student attempts
-    to make an in-app purchase. To avoid student confusion in the classroom,
-    also recommend not including any in-app purchase buttons and other UI in
-    your application. We are investigating additional purchase mechanisms to
-    enable more flexible pricing models for developers and schools.
-  </dd>
+<p>
+  <strong>Why is it recommended that in-app purchase features are
+  removed?</strong>
+</p>
 
-  <dt>
-    Is Google Play for Education restricted so only its users can purchase from
-    the Google Play for Education? Or will anyone be able to purchase from it?
-  </dt>
+<p>
+  In-app Billing is currently not supported with Google Play for Education, and
+  a student device will block the Google Play transaction if a student attempts
+  to make an in-app purchase. To avoid confusing students, we recommend not
+  including any in-app purchase buttons and other UI in your apps. We’re
+  investigating additional purchase mechanisms to enable more flexible pricing
+  models for developers and schools.
+</p>
 
-  <dd>
-    Currently, only schools that are signed up for Google Play for Education
-    can make purchases on it.
-  </dd>
+<p>
+  <strong>Is Google Play for Education restricted so only its users can
+  purchase from the Google Play for Education? Or will anyone be able to
+  purchase from it?</strong>
+</p>
 
-  <dt>
-    Is there a way to differentiate an app's pricing between Google Play for
-    Education and Google Play?
-  </dt>
+<p>
+  Currently, only schools that are signed up for Google Play for Education can
+  make purchases on it.
+</p>
 
-  <dd>
-    For each app that you publish, you can set a single price that applies to
-    both Google Play and Google Play for Education &mdash. You can’t set a
-    different price for a given app (based on a single package name) in Google
-    Play for Education.
-  </dd>
-</dl>
+<p>
+  <strong>Can I set different prices for my apps in Google Play for Education
+  and Google Play?</strong>
+</p>
 
+<p>
+  You set a single price for each app that applies to both Google Play and
+  Google Play for Education. You can’t set a different price for a given app
+  (based on a single package name) in Google Play for Education.
+</p>
 
-<h2 id="free_trials">Free Trials</h2>
+<div class="headerLine">
+  <h1 id="free-trials">
+  Free Trials
+  </h1>
 
-<dl>
-  <dt>
-    Can I offer free trials through Google Play for Education?
-  </dt>
+  <hr>
+</div>
 
-  <dd>
-    Google Play for Education doesn't currently support free trials. If you
-    want, you can offer a free version of your app with limited functionality
-    in Google Play for Education, but that app would need to be separate from
-    your paid app and be reviewed separately for educational content.
-  </dd>
+<p>
+  <strong>Can I offer free trials through Google Play for Education?</strong>
+</p>
 
-  <dt>
-    Can I offer a free trial through Google Play's "In-app Subscriptions with
-    Free Trials" feature?
-  </dt>
+<p>
+  Google Play for Education doesn't currently support free trials. If you want,
+  you can offer a free version of your app with limited functionality in Google
+  Play for Education, but that app would need to be separate from your paid app
+  and be reviewed separately for educational content.
+</p>
 
-  <dd>
-    Google Play for Education does not currently support In-app Billing or
-    In-app Subscriptions with free trials.
-  </dd>
-</dl>
+<p>
+  <strong>Can I offer a free trial through Google Play's "In-app Subscriptions
+  with Free Trials" feature?</strong>
+</p>
 
+<p>
+  Google Play for Education doesn’t currently support In-app Billing or In-app
+  Subscriptions with free trials.
+</p>
 
-<h2 id="discovery">Discovery</h2>
+<div class="headerLine">
+  <h1 id="discovery">
+  Discovery
+  </h1>
 
-<dl>
-  <dt>
-    What are the categories in Google Play for Education?
-  </dt>
+  <hr>
+</div>
 
-  <dd>
-    Google Play for Education includes categories for all grade levels from
-    Kindergarten to 12 and the following subjects: English Language Arts, World
-    Languages, Mathematics, Science, Social Science, Elective, OER (Open
-    Education Resources), and Tools.
-  </dd>
+<p>
+  <strong>What are the categories in Google Play for Education?</strong>
+</p>
 
-  <dt>
-    I created an app specifically for Google Play for Education and do not want
-    it to show up in Google Play. Is this possible?
-  </dt>
+<p>
+  Google Play for Education includes categories for all grade levels from
+  Kindergarten to 12 and the following subjects: English Language Arts, World
+  Languages, Mathematics, Science, Social Science, Elective, Open Education
+  Resources (OER), and Tools.
+</p>
 
-  <dd>
-    Currently, it is not possible to publish an app Google Play for Education
-    and make it unavailable on Google Play.
-  </dd>
+<p>
+  <strong>I created an app specifically for Google Play for Education and don’t
+  want it to show up in Google Play. Is this possible?</strong>
+</p>
 
-  <dt>
-    If my app offers content for every level of education, how will it fit the
-    common-core standard filters?
-  </dt>
+<p>
+  Currently, it’s not possible to publish an app on Google Play for Education
+  and make it unavailable on Google Play.
+</p>
 
-  <dd>
-    If your app applies to multiple levels of education, then the app will show
-    up filtered results for in multiple levels.
-  </dd>
-</dl>
+<p>
+  <strong>If my app offers content for every level of education, how will it
+  fit the Common Core State Standard filters?</strong>
+</p>
 
+<p>
+  If your app applies to multiple levels of education, then the app will show
+  up in filtered results for multiple levels.
+</p>
 
-<h2 id="reviews">App Review Process</h2>
+<div class="headerLine">
+  <h1 id="app-review-process">
+  App Review Process
+  </h1>
 
-<dl>
-  <dt>
-    How are apps being reviewed? By whom and with what criteria?
-  </dt>
+  <hr>
+</div>
 
-  <dd>
-    Apps are being reviewed by a third party network of educators. These
-    educators assign the appropriate subject, grade, and common core standards
-    metadata, as well as evaluating whether the app meets the Google Play for
-    Education <a href=
-    "{@docRoot}distribute/googleplay/edu/guidelines.html">criteria for
-    classroom use</a>. You can learn more about the submission process and
-    criteria at <a href=
-    "http://developer.android.com/edu">developer.android.com/edu</a>.
-  </dd>
+<p>
+  <strong>How are apps being reviewed? By whom and against what
+  criteria?</strong>
+</p>
 
-  <dt>
-    How do I update my apps in Google Play for Education?
-  </dt>
+<p>
+  Apps are being reviewed by a third-party network of educators. These
+  educators assign the appropriate subject, grade, and Common Core State
+  Standards metadata, as well as evaluating whether the app meets the Google
+  Play for Education <a href=
+  "{@docRoot}distribute/essentials/gpfe-guidelines.html">criteria for classroom
+  use</a>.
+</p>
 
-  <dd>
-    Developers can update their apps on Google Play for Education in the same
-    manner that they do for Google Play. App updates will not be reviewed prior
-    to being made available through Play for Education. However, we will
-    periodically review updated apps for quality.
-  </dd>
+<p>
+  <strong>How do I update my apps in Google Play for Education?</strong>
+</p>
 
-  <dt>
-    Does the app maturity rating reflect solely what a user can do within my
-    Android app, or does the web version of my app influence the rating as
-    well?
-  </dt>
+<p>
+  You can update your apps on Google Play for Education in the same manner you
+  do on Google Play. App updates will not be reviewed prior to being made
+  available through Google Play for Education. However, we will periodically
+  review updated apps for quality.
+</p>
 
-  <dd>
-    The maturity rating that you set for your Android app refers only to the
-    content displayed in that application.
-  </dd>
-</dl>
+<p>
+  <strong>Does the app maturity rating reflect solely on what a user can do
+  within my Android app, or does the web version of my app influence the rating
+  as well?</strong>
+</p>
 
+<p>
+  The maturity rating that you set for an Android app refers only to the
+  content displayed in that app.
+</p>
 
-<h2 id="features">App Features</h2>
+<div class="headerLine">
+  <h1 id="app-features">
+  App Features
+  </h1>
 
-<dl>
-  <dt>
-    Do I need separate builds of my phone and tablet apps for Google Play for
-    Education, or is it the exact same app that lives on Google Play?
-  </dt>
+  <hr>
+</div>
 
-  <dd>
-    We recommend you create one app and use it in both Google Play and Google
-    Play for Education.
-  </dd>
+<p>
+  <strong>Do I need separate builds of my phone and tablet apps for Google Play
+  for Education, or is it the exact same app that lives on Google
+  Play?</strong>
+</p>
 
-  <dt>
-    What is the best way to get students’ work within apps sent back to their
-    teachers?
-  </dt>
+<p>
+  We recommend you create one app and use it in both Google Play and Google
+  Play for Education.
+</p>
 
-  <dd>
-    Many teachers have mentioned that the way apps treat this now is via an
-    email from a third party, which is not optimal for schools. As many schools
-    use Google Apps for Education, consider integrating your app with Google
-    Drive using the SDK which can be found here: <a class="external-link" href=
-    "https://developers.google.com/drive/about-sdk">developers.google.com/drive/about-sdk</a>.
-  </dd>
+<p>
+  <strong>What is the best way to get students’ work within apps sent back to
+  their teachers?</strong>
+</p>
 
-  <dt>
-    How can developers test the teacher experience in Google Play for
-    Education? Is there a way to get an account to test it?
-  </dt>
+<p>
+  Teachers have mentioned that many apps achieve this by email from a third
+  party, which isn’t optimal for schools. As many schools use Google Apps for
+  Education, consider integrating your apps with Google Drive using the
+  <a href="https://developers.google.com/drive/about-sdk">SDK</a>.
+</p>
 
-  <dd>
-    Currently, we are unable to provide developers with a test account to test
-    the Google Play for Education user experience. We are investigating ways to
-    allow developers to simulate the environment.
-  </dd>
+<p>
+  <strong>How can developers test the teacher experience in Google Play for
+  Education? Is there a way to get an account to test it?</strong>
+</p>
 
-  <dt>
-    If I already have an app in the Chrome Apps Pack will I get some help
-    migrating this to Android?
-  </dt>
+<p>
+  Currently, we are unable to provide developers with a test account to test
+  the Google Play for Education user experience. We’re investigating ways to
+  allow developers to simulate the environment.
+</p>
 
-  <dd>
-    If you’d like to reach tablet users in schools we encourage you
-    to build a native app for the optimal user experience. Considerations for
-    building your app and instructions for registering it can be found at
-    <a href="http://developer.android.com/edu">developer.android.com/edu</a>.
-  </dd>
-</dl>
+<p>
+  <strong>If I already have an app in the Chrome Apps Pack will I get some help
+  migrating this to Android?</strong>
+</p>
 
+<p>
+  If you’d like to reach tablet users in schools we encourage you to build a
+  native app for the optimal user experience. Considerations for building your
+  apps can be found in the <a href=
+  "{@docRoot}distribute/essentials/gpfe-guidelines.html">Google Play for
+  Education Guidelines</a>.
+</p>
 
-<h2 id="marketing">Marketing and ROI</h2>
+<div class="headerLine">
+  <h1 id="marketing-and-roi">
+  Marketing and ROI
+  </h1>
 
-<dl>
-  <dt>
-    What are you doing to promote these apps to educators?
-  </dt>
+  <hr>
+</div>
 
-  <dd>
-    Google Play for Education is an extension of Google Play targeting schools
-    and making discovery easier for educational apps. It helps your apps gain
-    visibility with the right audiences, without having to knock on school
-    doors. We are constantly referring to the highest quality apps in our
-    educator outreach. We have also developed a series of collections to help
-    educators quickly browse apps for the most common use cases.
-  </dd>
+<p>
+  <strong>What are you doing to promote these apps to educators?</strong>
+</p>
 
-  <dt>
-    How many installs have similar apps had on Play? How much can I expect to
-    make if I do an ROI analysis?
-  </dt>
+<p>
+  Google Play for Education is an extension of Google Play targeting schools
+  and making the discovery of educational apps easier. It helps your apps gain
+  visibility with the right audiences, without having to knock on school doors.
+  We’re constantly referring to the highest quality apps in our educator
+  outreach. We’ve also developed a series of collections to help educators
+  quickly browse apps for the most common use cases.
+</p>
 
-  <dd>
-    While we cannot disclose specific numbers, Google Play app listings provide
-    app download ranges for all apps.
-  </dd>
+<p>
+  <strong>How many installs have similar apps had on Google Play for Education?
+  How much can I expect to make if I do an ROI analysis?</strong>
+</p>
 
-  <dt>
-    What is the seasonality like for the education market? What are the key
-    timing considerations for app developers?
-  </dt>
+<p>
+  While we cannot disclose specific numbers, Google Play app listings provide
+  app download ranges for all apps.
+</p>
 
-  <dd>
-    In the United States, school districts’ budget decisions go through a
-    planning phase in the Spring with budgets being released on July 1. We have
-    observed high purchase-volumes in the second quarter of the calendar year,
-    using up end-of-year budgets. New budget purchases begin in the third
-    quarter of the calendar year.
-  </dd>
+<p>
+  <strong>What is the seasonality like for the education market? What are the
+  key timing considerations for app developers?</strong>
+</p>
 
-  <dt>
-    Is there a way to offer a special deal, such as a discount, only on Google
-    Play for Education and not on Google Play?
-  </dt>
+<p>
+  In the United States, school districts’ budget decisions go through a
+  planning phase in the Spring with budgets being released on July 1. We’ve
+  observed high purchase-volumes in the second quarter of the calendar year, to
+  use up end-of-year budgets. New budget purchases begin in the third quarter
+  of the calendar year.
+</p>
 
-  <dd>
-    No, this is not possible. Pricing, including special offers, must be the
-    same between Google Play for Education and Google Play.
-  </dd>
-</dl>
+<p>
+  <strong>Is there a way to offer a special deal, such as a discount, only on
+  Google Play for Education and not on Google Play?</strong>
+</p>
 
+<p>
+  No, this isn’t possible. Pricing, including special offers, must be the same
+  between Google Play for Education and Google Play.
+</p>
 
-<h2 id="devices">Devices</h2>
+<div class="headerLine">
+  <h1 id="devices">
+  Devices
+  </h1>
 
-<dl>
-  <dt>
-    Which devices are available in the program? Will more be available?
-  </dt>
+  <hr>
+</div>
 
-  <dd>
-    Nexus 7 is available for shipment now, and the Asus Transformer and HP
-    Slate 8 Pro will be available in early 2014. We look forward to welcoming
-    more Android devices into the Google in Education family soon.
-  </dd>
+<p>
+  <strong>Which devices are available in the program? Will more be
+  available?</strong>
+</p>
 
-  <dt>
-    Can the devices be shared among many students?
-  </dt>
+<p>
+  Nexus 7 is available for shipment now, and the Asus Transformer, HP Slate 8
+  Pro, and Galaxy Tab for Education will be available in early 2014. We look
+  forward to welcoming more Android devices into the Google in Education family
+  soon.
+</p>
 
-  <dd>
-    No. Currently, this program is for one-to-one usage. Each student can login
-    to one specific tablet that is allocated to them.
-  </dd>
-</dl>
+<p>
+  <strong>Can the devices be shared among many students?</strong>
+</p>
 
+<p>
+  No. Currently, this program is for one-to-one use. Each student can login to
+  one specific tablet that is allocated to them.
+</p>
 
-<h2 id="accounts">
+<div class="headerLine">
+  <h1 id="accounts">
   Accounts
-</h2>
+  </h1>
 
-<dl>
-  <dt>
-    Will an app know whether a user is a teacher or student?
-  </dt>
+  <hr>
+</div>
 
-  <dd>
-    No, the app has no mechanism for knowing if it is running on a teacher’s
-    device or a student’s device. We recommend developers use their own user
-    database to enable this feature, where logins can be based on Google
-    Account information.
-  </dd>
+<p>
+  <strong>Will an app know whether a user is a teacher or student?</strong>
+</p>
 
-  <dt>
-    What log-in method do you recommend for an app on Google Play for
-    Education?
-  </dt>
+<p>
+  No, the app has no mechanism for knowing if it’s running on a teacher’s
+  device or a student’s device. We recommend developers use their own user
+  database to enable this feature, where logins can be based on Google Account
+  information.
+</p>
 
-  <dd>
-    One of the key pieces of feedback we have heard multiple times from various
-    schools is that they prefer apps that offer Google Single Sign-on, so that
-    teachers and students do not need to remember multiple log-in credentials.
-    As schools in the program use Google Accounts and Google Apps for
-    Education, offering Google Single Sign-on is ideal.
-  </dd>
-</dl>
\ No newline at end of file
+<p>
+  <strong>What log-in method do you recommend for an app on Google Play for
+  Education?</strong>
+</p>
+
+<p>
+  One of the key pieces of feedback we’ve heard multiple times from various
+  schools is that they prefer apps that offer Google Single Sign-on, so that
+  teachers and students don’t need to remember multiple log-in credentials. As
+  schools in the program use Google Accounts and Google Apps for Education,
+  offering Google Single Sign-on is ideal.
+</p>
+<div class="headerLine"><h1 id="related-resources">Related Resources</h1><hr></div>
+
+<div class="resource-widget resource-flow-layout col-13"
+  data-query="collection:distribute/toolsreference/gpfefaq"
+  data-sortOrder="-timestamp"
+  data-cardSizes="6x3,6x3,6x3,9x3,9x3,9x3"
+  data-maxResults="6"></div>
+
diff --git a/docs/html/distribute/googleplay/edu/guidelines.jd b/docs/html/distribute/googleplay/edu/guidelines.jd
deleted file mode 100644
index 8427044..0000000
--- a/docs/html/distribute/googleplay/edu/guidelines.jd
+++ /dev/null
@@ -1,244 +0,0 @@
-page.title=Guidelines for Apps
-page.metaDescription=Get your apps ready for Google Play for Education.
-excludeFromSuggestions=true
-@jd:body
-
-   <div style="position:absolute;margin-left: 636px;
-            margin-top:-76px;color:#777;">If you're interested<br>
-            <a href="{@docRoot}distribute/googleplay/edu/contact.html"
-            class="go-link"
-            style="display: block;text-align: right;">SIGN UP</a></div>
-
-<div style="background-color:#fffdeb;width:100%;margin-bottom:1em;padding:.5em;">You
-can now include your educational apps in the recently launched Google Play for Education program,
-getting it into the hands of participating schools and key influencers in the education technology
-community. See <a href="start.html">Get Started</a> to
-learn how to participate. </div>
-
-<p>The sections below list the guidelines and requirements for apps
-participating in Google Play for Education.
-
-<p>Before you include your app in Google Play for Education, set up a <a
-href="#test-environment">test environment</a> and make sure your app meets all
-of the safety, usability, and quality guidelines given here. You can use the
-linked resources to help
-you develop a great app for students that offers compelling content and an
-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
-the standard  <a
-href="http://play.google.com/about/developer-content-policy.html"
-target="_policies">Google Play Developer Program Policies</a> and <a
-href="http://play.google.com/about/developer-distribution-agreement.html"
-target="_policies">Developer Distribution Agreement</a>.</p>
-
-
-<h2 id="requirements">Safety First</h2>
-
-<p>To participate, your apps must be designed to be appropriate for
-the K-12 market. The basic requirements that your apps must meet are:</p>
-
-<ol>
-  <li>Apps and the ads they contain must not collect personally identifiable
-information other than user credentials or data required to operate and improve
-the app.</li>
-  <li>Apps must not use student data for purposes unrelated to its educational
-function.</li>
-  <li>Apps must have a content rating of "Everyone" or "Low Maturity" (apps with
-a "Medium Maturity" rating are allowed, if they have that rating solely because
-they allow communication between students).</li>
-  <li>App content, including ads displayed by the app, must be consistent with
-the app's maturity rating. The app must not display any “offensive” content, as
-described in the <a
-href="http://play.google.com/about/developer-content-policy.html">Google Play
-Developer Program Policies</a> and <a
-href="https://support.google.com/googleplay/android-developer/answer/188189">
-content-rating guidelines</a>.</p></li>
-<li>Apps must comply with the Children’s Online Privacy Protection Act
-and all other applicable laws and regulations.</li>
-</ol>
-
-
-<h2 id="inapp">Monetizing and Ads</h2>
-
-<p>Google Play for Education provides a simple and secure environment for students
-and teachers. To support that environment, priced or free apps that do not use in-app
-purchases are preferred, as are apps that do not display ads. Apps that use in-app
-payments or ads are acceptable, but you must declare those behaviors when opting-in
-to Google Play for Education. Your app's use of in-app purchases or ads will be
-disclosed to educators when they are browsing for content.</p>
-
-<p>Follow the guidelines below to help your app receive the
-  highest ratings and offer the best possible user-experience.</p>
-
-<p>If your app is priced or sells in-app products, you must:</p>
-
-<ul>
-  <li>Sell all content and services through Google Play for Education</li>
-  <li>Allow Google Play to offer teachers limited free trials before purchase
-(through business terms only, no development work is needed)</li>
-<li>Disable in-app purchases if possible, or ensure that:
-
-<ul>
-<li>Users can access your app's core functionality for a classroom setting without
-an in-app purchase.</li>
-<li>In-app purchases are clearly identifiable in your UI.</li>
-<li>You declare the use of in-app purchases at <a href="{@docRoot}distribute/googleplay/edu/start.html#opt-in">opt-in</a>.</li>
-</ul>
-</li>
-</ul>
-
-<p class="note"><strong>Note</strong>: In-app
-purchases are blocked on Google Play for Education tablets at this time.</p>
-
-<p>If your app displays ads, you should:
-  <ul>
-  <li>Disable the display of ads if possible, or ensure that:
-  <ul>
-    <li>Ads are not distracting for students or teachers</li>
-    <li>Ads do not occupy a significant portion of the screen</li>
-    <li>Ads content does not exceed the maturity rating of the app.</li>
-    <li>You declare the use of ads at <a href="{@docRoot}distribute/googleplay/edu/start.html#opt-in">opt-in</a>.</li>
-  </ul>
-  </li>
-</ul>
-
-
-<h2 id="approved">Educational Value</h2>
-
-<p>Apps submitted to Google Play for Education will be evaluated by a
-third-party educator network, which will review them based on alignment with <a
-href="http://www.corestandards.org/" class="external-link"
-target="_android">Common Core Standards</a> and other factors. This will help
-make your content more discoverable for teachers and administrators as they
-browse by grade level, subject, core curriculum, and other parameters. </p>
-
-<p>Apps with highest educational value will have these characteristics:</p>
-<ul>
-  <li>Designed for use in K-12 classrooms.</li>
-  <li>Aligned with a common core standard or support common-core learning.</li>
-  <li>Simple, easy to use, and intuitive for the grade levels the app is targeting.
-  App is relatively easy to navigate without teacher guidance. Not distracting
-  or overwhelming to students.</li>
-  <li>Enjoyable and interactive. App is engaging to students and lets them control
-  their experience.</li>
-  <li>Versatile. App has features make the it useful for more than one classroom
-  function or lesson throughout the school year.</li>
-  <li>Supports the "4Cs":
-    <ul>
-    <li><em>Creativity</em> &mdash; Allows students to create in order to express
-    understanding of the learning objectives, and try new approaches, innovation
-    and invention to get things done.</li>
-    <li><em>Critical thinking</em> &mdash; Allows students to look at problems in
-    a new way, linking learning across subjects and disciplines.</li>
-    <li><em>Collaboration</em> &mdash; Allows students and (if appropriate) educators
-    to work together to reach a goal.</li>
-    <li><em>Communication</em> &mdash; Allows students to comprehend, critique and
-    share thoughts, questions, ideas and solutions.</li>
-    </ul>
-  </li>
-</ul>
-
-<p>As you design and develop your app, make sure it offers high educational value
-by addressing as many of those characteristics as possible.</p>
-
-
-<h2 id="quality">App Quality</h2>
-
-<p>Google Play for Education brings educational content to students and teachers
-on Android tablets. Your apps should be designed to perform well and look great
-on Android tablets, and they should offer the best user experience possible.
-</p>
-
-<p>High quality apps are engaging, intuitive, and offer compelling content.
-Google Play for Education will highlight high-quality apps for easy discovery in
-the store. Here are some recommendations for making your app easy for students
-and teachers to enjoy.</p>
-
-<ul>
-  <li>Meet Core app quality guidelines
-    <ul>
-      <li>Follow <a
-      href="{@docRoot}design/index.html">Android Design Guidelines</a>. Pay special
-      attention to the sections on <a href="{@docRoot}design/patterns/actionbar.html">Action
-      Bar</a>, <a href="{@docRoot}design/patterns/navigation.html">Navigation</a> and <a
-      href="{@docRoot}design/patterns/pure-android.html">Pure Android</a>.</li>
-      <li>Test your apps against the <a href="{@docRoot}distribute/googleplay/quality/core.html">Core
-      App Quality Guidelines</a>.</li>
-    </ul>
-  </li>
-<li>Meet tablet app quality guidelines
-  <ul>
-   <li>Follow our best practices for tablet app development</li>
-   <li>Review the <a href="{@docRoot}distribute/googleplay/quality/tablet.html">Tablet App
-   Quality Checklist</a> and <a
-   href="http://android-developers.blogspot.com/2012/11/designing-for-tablets-were-here-to-help.html"
-   target="_android">blog post on designing for tablets</a></li>
-   <li>Check your Optimization Tips in the Google Play Developer Console (if you've
-   already uploaded your app)</li>
-  </ul>
-<li>Strive for simplicity and highest usability for students
-  <ul>
-    <li>Design your app so that teachers and students can use all capabilities of
-    your app without having to sign-in to multiple accounts and remember
-    multiple passwords.</li>
-    <li>Every student or teacher using a Google Play for Education tablet will already be
-    signed in with a Google account on the device.  You can take advantage of that to provide a
-    simple, seamless sign-in experience in your app. A recommended approach is to use
-    <a href="{@docRoot}google/play-services/auth.html">Google OAuth 2 authorization</a>
-    through Google Play Services.</li>
-  </ul>
-</li>
-</ul>
-
-
-<h2 id="test-environment">Test Environment</h2>
-
-<p>To test your app and assess it against the guidelines in this document, it's
-recommended that you set up a test environment that replicates the actual
-environment in which students and teachers will run your app.</p>
-
-<p>In general, you should use the test environment described in <a
-href="{@docRoot}distribute/googleplay/quality/tablet.html#test-environment">
-Setting Up a Test Environment for Tablets</a>, including a small number of
-actual hardware devices that replicate the tablet form factors used in the
-Google Play for Education.</p>
-
-<h3 id="devices">Android tablets</h3>
-
-<p>Google Play for Education offers a range of 7-inch through 10-inch tablets, so
-your testing should focus on those hardware devices. You can purchase the Nexus 7
-device from <a href="https://play.google.com/store/devices/details?id=nexus_7_16gb"
-target="_android">Google Play</a> and other stores. Although testing on Nexus
-devices is preferred, you can test on other 7-inch or 10-inch tablets or virtual
-devices if you don't have access to Nexus devices.</p>
-
-<h3 id="conditions">Test conditions</h3>
-
-<p>Once you've set up a suitable hardware environment, make sure to test your
-apps under conditions that simulate those of schools. For example, Google Play
-for Education lets administrators control or disable certain capabilities for
-students, so it's good to test your app with those capabilities disabled. Below
-are some conditions to test your app in, to ensure best results in the Google
-Play for Education environment:</p>
-
-<ul>
-<li><em>Android version</em> &mdash; Test the app on devices running Android
-4.2. Google Play for Education devices will be running Android 4.2 or higher
-(API level 17+).</li>
-<li><em>Proxy server</em> &mdash; Test the app in network environment that uses
-proxies. Many schools use proxies.</li>
-<li><em>No location services</em> &mdash; Test the app to make sure it works
-properly with location services disabled. Many schools will disable location
-services for student devices.</li>
-<li><em>No In-app Billing</em> &mdash; Test the app to make sure it works
-properly without access to In-app Billing. In-app purchases are blocked on
-Google Play for Education devices at this time.</li>
-<li><em>No Bluetooth</em> &mdash; Test the app to make sure it works properly
-when Bluetooth is disabled. Many schools will disable Bluetooth on student
-devices.</li>
-<li><em>No access to network</em> &mdash; Test the app to make sure it works
-properly when the device cannot connect to the internet. </li>
-</ul>
diff --git a/docs/html/distribute/googleplay/edu/index.jd b/docs/html/distribute/googleplay/edu/index.jd
deleted file mode 100644
index 487028f..0000000
--- a/docs/html/distribute/googleplay/edu/index.jd
+++ /dev/null
@@ -1,48 +0,0 @@
-page.title=Google Play for Education
-page.tags="Google Play","education","schools", "distribution"
-header.hide=1
-
-@jd:body
-    <div style="position:absolute;margin-left: 636px;
-            margin-top:6px;color:#777;">If you're interested<br>
-            <a href="{@docRoot}distribute/googleplay/edu/contact.html"
-            class="go-link"
-            style="display: block;text-align: right;">SIGN UP</a></div>
-
-   <div class="marquee">
-  <div class="mainimg" style="position:absolute;margin-left:34px;margin-top:57px;">
-    <img src="{@docRoot}images/gp-edu-hero14.jpg" style="width:670px;" />
-  </div>
-  <div class="copy" style="position:relative;left:334px;margin-top:28px;width:420px;">
-    <h1 style="margin-bottom:10px;">Google Play for Education</h1>
-    <p>Google Play for Education is a destination where schools can find great,
-    teacher-approved, educational apps and videos on Play Store. Teachers can filter
-    content by subject matter, grade and other criteria. Bulk purchase and instant
-    distribution let educators bring your apps directly to classrooms and schools.</p>
-    <p>If you have an educational app, join Google Play for Education.</p>
-    <p><a class="button" href="{@docRoot}distribute/googleplay/edu/about.html">Learn More</a></p>
-  </div>
-</div>
-
-<div class="distribute-features col-13" style="clear:both;margin-top:248px;">
-  <div class="distribute-link">
-  <ul>
-    <li><a href="{@docRoot}distribute/googleplay/edu/about.html"><h5>About the Initiative</h5>
-    Find out how Google Play for Education helps you reach a new audience of educators and students.</a>
-    <li><a href="{@docRoot}distribute/googleplay/edu/start.html"><h5>Get your Apps Ready</h5> 
-    Follow these guidelines to make sure your app meets requirements and offers a great user experience. </a>
-    </li>
-    <li class="last"><a href="{@docRoot}distribute/googleplay/edu/start.html#opt-in"><h5>Submit your App</h5>
-    Use the Google Play Developer Console to mark your app for inclusion in the program and review by third-party
-    educators. </a>
-    </li>
-  </ul>
-  </div>
-
-</div>
-
-
-    
-
-
-
diff --git a/docs/html/distribute/googleplay/edu/start.jd b/docs/html/distribute/googleplay/edu/start.jd
index dbfbb6a..260ae85 100644
--- a/docs/html/distribute/googleplay/edu/start.jd
+++ b/docs/html/distribute/googleplay/edu/start.jd
@@ -1,233 +1,320 @@
-page.title=Get Started
-page.metaDescription=Get Started with Google Play for Education
-excludeFromSuggestions=true
+page.title=Get Started with Education
+page.image=/distribute/images/play-education.jpg
+meta.tags="education", "guidelines", "quality"
+page.tags="education", "addendum"
+page.metaDescription=Join Google Play for Education in just a few simple steps.
+
 @jd:body
 
-    <div class="jd-descr" itemprop="articleBody">
-    <div style="position:absolute;margin-left: 636px;
-            margin-top:-76px;color:#777;">If you're interested<br>
-            <a href="{@docRoot}distribute/googleplay/edu/contact.html"
-            class="go-link"
-            style="display: block;text-align: right;">SIGN UP</a></div>
-
-<div style="background-color:#fffdeb;width:100%;margin-bottom:1em;padding:.5em;">You
-can now include your educational apps in the Google Play for Education program,
-getting it into the hands of participating schools and key influencers in the
-education technology community. See the sections below to learn more.</div>
-
-<p>If you've got a great app for education, be
-part of Google Play for Education to reach even more teachers and students. It's
-easy to participate, and you'll be able to offer new or existing Android apps
-using familiar tools and processes in Google Play.</p>
-
-<p>To get started, review the sections in this document and learn how to make
-your apps available through Google Play for Education. Also make sure to read <a
-href="{@docRoot}distribute/googleplay/edu/guidelines.html">Guidelines for
-Apps</a>  for information on the safety, usability, and quality standards that
-your apps should meet. When your app is ready, you can opt-in to Google Play for
-Education from the Developer Console.</p>
-
-<p>Note that Google Play for Education is currently available to schools in the
-United States only, with support for schools in other
-countries to follow. At this time, please include your app in Google Play for
-Education only if it is targeting the <strong>US K-12 market</strong>. </p>
-
-
-<h2 id="participate">How to Participate</h2>
-
-<div style="float:right; padding-top:2em;"><img
-src="{@docRoot}images/gp-edu-process.png" /></div>
-
-<p>Google Play for Education is a great way to put your educational apps in front of a
-new audience of teachers and students. You can develop and publish using
-familiar tools and processes, such as your existing <a
-href="https://play.google.com/apps/publish/">Developer Console</a> account
-and your current distribution and pricing settings. It's easy to participate
-&mdash; the sections below outline the process.</p>
-
-<h3 id="basic-info">1. Understand guidelines and policies</h3>
-
-<p>To prepare for a successful launch on Google Play for Education, start by
-reviewing the guidelines for educational apps in Google Play and the policies
-that apply to your apps. See <a
-href="{@docRoot}distribute/googleplay/edu/guidelines.html">Guidelines for
-Apps</a> for details.</p>
-
-<p>Also, make sure that your are familiar with the policies that your app must
-comply with, including
-<a href="http://play.google.com/about/developer-content-policy.html" target="_policies">content
-policies</a>, the <a
-href="http://play.google.com/about/developer-distribution-agreement.html"
-target="_policies">developer agreement</a>,  and <a
-href="https://play.google.com/about/developer-distribution-agreement-addendum.html"
-target="_policies">Google Play for Education Addendum</a>.</p>
-
-<h3 id="developing">2. Design and develop a great app for education</h3>
-
-<p>A great app for educators and students is designed for classroom use, looks
-great on tablets, and delivers a compelling feature set for teachers and
-students. If you are developing an app for education, make sure that it is
-appropriate for K-12 classrooms, offers educational value, and is refined to
-offer a polished, high-quality tablet experience.</p>
-
-<p>Assess your app against the criteria listed in <a
-href="{@docRoot}distribute/googleplay/edu/guidelines.html">Guidelines for
-Apps</a> and plan on supporting them to the greatest extent possible. In some
-cases you might need to modify your features or UI to support the requirements
-of the classroom use-case. It's a good idea to identify those areas early in
-development so that you are able address them properly. </p>
-
-<p>With Google Play for Education, optimizing your app for tablets is a crucial
-part of getting your app ready for distribution to educators. A variety of
-resources are available to help you understand what you need to optimize for
-tablets &mdash; a good starting point is the <a
-href="{@docRoot}distribute/googleplay/quality/tablet.html">Tablet App Quality
-Guidelines</a>. </p>
-
+<div id="qv-wrapper"><div id="qv">
+<h2>Steps to Join</h2>
+<ol>
+<li><a href="#register">Register for a Publisher Account</li>
+<li><a href="#prepare">Prepare Your Apps</a></li>
+<li><a href="#publish">Publish Your Apps</a></li>
+<li><a href="#related-resources">Related Resources</a></li>
+</ol>
+</div></div>
 <p>
-  Throughout design and development, it's important to have suitable devices
-  on which to prototype and test your user experience. It's highly recommended
-  that you acquire 7-inch and 10-inch tablet devices and set up
-  your testing environment as early as possible. The recommended 7-inch
-  hardware device that replicates the Google Play for Education environment is
-  the Nexus 7, which is available from <a href=
-  "https://play.google.com/store/devices/details?id=nexus_7_16gb" target=
-  "_android">Google Play</a> and other stores.
+  If you've got great apps for education and want to reach even more teachers
+  and students, you can join the <strong>Google Play for Education</strong>
+  program in a few simple steps. You do everything using the familiar tools and
+  processes in Google Play.
 </p>
 
-<p>Proper testing and quality assurance are key aspects of delivering a great
-app for teachers and students. Make sure you set up a <a
-href="{@docRoot}distribute/googleplay/edu/guidelines.html#test-environment">
-proper test environment</a> to ensure that your app meets guidelines under
-realistic conditions.</p>
+<p>
+  Note that Google Play for Education is currently available to <strong>K-12
+  schools in the United States</strong> only.
+</p>
 
-<h3 id="opt-in">3. Opt-in to Google Play for Education and publish</h3>
-
-<div class="sidebox-wrapper">
-<div class="sidebox">
-<h2>Before you opt-in</h2>
-<p>To participate in Google Play for Education, you must agree to a <a
-href="https://play.google.com/about/developer-distribution-agreement-addendum.html"
-target="_policies">Google Play for Education Addendum</a>
-to the standard Developer Distribution Agreement.</p>
-
-<p>Before you opt-in, review the Addendum completely and make any necessary
-modifications to your app.</p>
-</div>
+<div class="center-img">
+  <img src="{@docRoot}images/gpfe-start-0.jpg" style=
+  "border:1px solid #ddd;padding:0px;width:100%;">
 </div>
 
-<p>Once you've built your release-ready APK and tested to ensure that it meets
-the <a href="{@docRoot}distribute/googleplay/edu/guidelines.html">app guidelines</a>,
-upload it to the Developer Console, create your store listing, and set
-distribution options. If you aren't familiar with how to prepare for launch on
-Google Play, see the <a
-href="{@docRoot}distribute/googleplay/publish/preparing.html">Launch Checklist</a>. </p>
+<div class="headerLine clearfloat">
+  <h1 id="register">
+    Register for a Publisher Account
+  </h1>
 
-<p>When your app is ready to publish, you can <em>opt-in</em> to Google Play for
-Education directly from the <a
-href="https://play.google.com/apps/publish/">Developer Console</a>. Opt-in means that you want your app to be
-made available to educators through Google Play for Education, including review,
-classification, and approval by our third-party educator network. Note that
-opt-in does not affect the availability of your app in Google Play Store.</p>
+  <hr>
+</div>
 
-<p>Opt-in also confirms that your app complies with <a
-href="http://play.google.com/about/developer-content-policy.html"
-target="_policies">Google Play Developer Program
-Policies</a> and the <a
-href="http://play.google.com/about/developer-distribution-agreement.html"
-target="_policies">Developer Distribution Agreement</a>,
-including a <a
-href="https://play.google.com/about/developer-distribution-agreement-addendum.html"
-target="_policies">Google Play for Education
-Addendum</a>. If you are not familiar with these policy documents or the
-Addendum, make sure to read them before opting-in. </p>
+<p>
+  If you’re new to Google Play, review the information on <a href=
+  "{@docRoot}distribute/googleplay/start.html">getting started</a> with
+  publishing on Google Play. You’ll gain access to the <a href=
+  "{@docRoot}distribute/googleplay/developer-console.html">Developer
+  Console</a>, where you’ll manage your details, apps, and payments.
+</p>
 
-<p>Here's how to opt-in to Google Play for Education for a specific app:</p>
+<div class="headerLine">
+  <h1 id="prepare">
+    Prepare Your Apps
+  </h1>
+
+  <hr>
+</div>
+
+<div class="figure-right">
+  <img src="{@docRoot}images/gp-edu-process.png">
+</div>
+
+<p>
+  By participating in Google Play for Education you’ll be placing your apps
+  before a new audience of teachers and educators. To address this audience,
+  there are specific guidelines and policies your apps should meet and specific
+  design considerations too.
+</p>
+
+<h3>
+  Understand guidelines and policies
+</h3>
+
+<p>
+  To prepare for a launch on Google Play for Education, start by reviewing the
+  guidelines for educational apps in Google Play and the policies that apply to
+  your apps. See the <a href=
+  "{@docRoot}distribute/essentials/gpfe-guidelines.html">Education
+  Guidelines</a> for details.
+</p>
+
+<p>
+  Also, make sure that you're familiar with the policies that your app must
+  comply with, including <a href=
+  "http://play.google.com/about/developer-content-policy.html">content
+  policies</a>, the <a href=
+  "http://play.google.com/about/developer-distribution-agreement.html">Developer
+  Distribution Agreement</a>, and <a href=
+  "https://play.google.com/about/developer-distribution-agreement-addendum.html">
+  Google Play for Education Addendum</a>.
+</p>
+
+<h3>
+  Design and develop a great app for education
+</h3>
+
+<p>
+  Great apps for educators and students <strong>offer educational
+  value</strong>, are <strong>designed for K-12 classroom use</strong>,
+  <strong>deliver a compelling feature set</strong>, and are refined to offer a
+  polished, <strong>high-quality tablet experience</strong>.
+</p>
+
+<p>
+  Assess your app against the criteria listed in the <a href=
+  "{@docRoot}distribute/essentials/gpfe-guidelines.html">Education
+  Guidelines</a> and plan on supporting them to the greatest extent possible.
+  In some cases you might need to modify the app’s features or UI to support
+  classroom requirements. It's a good idea to identify any changes early in
+  development, so that you can address them properly.
+</p>
+
+<p>
+  With Google Play for Education, optimizing your apps for tablets is crucial.
+  A variety of resources are available to help you understand what you need to
+  do — a good starting point is the <a href=
+  "{@docRoot}distribute/essentials/quality/tablets.html">Tablet App Quality</a>
+  guidelines.
+</p>
+
+<p>
+  Throughout design and development, it's important to have suitable devices on
+  which to prototype and test your user experience. It's recommended highly
+  that you acquire 7-inch and 10-inch tablet devices and set up your testing
+  environment as early as possible. The recommended 7-inch hardware device that
+  replicates the Google Play for Education environment is the Nexus 7, which is
+  available from <a href=
+  "https://play.google.com/store/devices/details?id=nexus_7_16gb_2013">Google
+  Play</a> and other stores.
+</p>
+
+<p>
+  Comprehensive testing and quality assurance are key aspects of delivering
+  great apps for teachers and students. Make sure you set up a <a href=
+  "{@docRoot}distribute/essentials/gpfe-guidelines.html#test-environment">proper
+  test environment</a> to, ensure that your apps meet the guidelines under
+  realistic conditions.
+</p>
+
+<div class="headerLine">
+  <h1 id="publish">
+    Publish Your Apps
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  Once you have designed, built, and tested your apps, you take two steps to
+  publish them:
+</p>
+
+<ul>
+  <li>Before you opt-in any apps, agree to the <a href=
+  "https://play.google.com/about/developer-distribution-agreement-addendum.html"
+    target="_policies">Google Play for Education Addendum</a>. Ensure you
+    review the Addendum completely and make any necessary modifications to your
+    apps.
+  </li>
+
+  <li>Publish your apps in the Developer Console as normal, but opt-in to
+  Google Play for Education.
+  </li>
+</ul>
+
+<h3 id="opt-in">
+  Opt-in to Google Play for Education and publish
+</h3>
+
+<p>
+  Once you've built your release-ready APK upload it to the Developer Console,
+  create your store listing, and set distribution options. If you aren't
+  familiar with preparing for launch on Google Play, see the <a href=
+  "{@docRoot}distribute/tools/launch-checklist.html">Launch Checklist</a>.
+</p>
+
+<div>
+  <img src="{@docRoot}images/gp-edu-optin-console.jpg" style=
+  "border:2px solid #ddd;width:660px;">
+</div>
+
+<p>
+  When your apps are ready to publish, you <em>opt-in</em> to Google Play for
+  Education directly from the <a href=
+  "https://play.google.com/apps/publish/">Developer Console</a>. Opt-in means
+  that you want your apps to be made available to educators through Google Play
+  for Education, including review, classification, and approval by our
+  third-party educator network. Note that opt-in doesn’t affect the
+  availability of your app in Google Play Store.
+</p>
+
+<p>
+  Opt-in also confirms that your app complies with <a href=
+  "http://play.google.com/about/developer-content-policy.html" target=
+  "_policies">Google Play Developer Program Policies</a> and the <a href=
+  "http://play.google.com/about/developer-distribution-agreement.html" target=
+  "_policies">Developer Distribution Agreement</a>, including a <a href=
+  "https://play.google.com/about/developer-distribution-agreement-addendum.html"
+  target="_policies">Google Play for Education Addendum</a>. If you are not
+  familiar with these policy documents or the Addendum, make sure to read them
+  before opting-in.
+</p>
+
+<p>
+  Here's how to opt-in to Google Play for Education for a specific app:
+</p>
 
 <ol>
-  <li>In the Developer Console All Applications page, click the app you want to
-opt-in. </li>
-  <li>Under Pricing and Distribution, scroll down to find "Google Play for
-Education" and the opt-in checkbox. </li>
-  <li>Click the checkbox next to "Include this application in Google Play for
-Education."</li>
-  <li>In the first dialog that appears, review the content policies and guidelines
-  and click "Continue" if your app meets the the policies and guidelines.</li>
-  <li>In next dialog that appears, shown below, find the "Ads" and "In-app purchases" radio
-  buttons. Check each option that applies. Your app's use of ads or in-app purchases will
-be shown to educators when they are browsing your app. </li>
-  <li>Click "Save" to save your Pricing and Distribution changes.</li>
+  <li>In the Developer Console <strong>All Applications</strong> page, click
+  the app you want to opt-in.
+  </li>
+
+  <li>Under Pricing and Distribution, scroll down to find <strong>Google Play
+  for Education</strong> and the opt-in checkbox.
+  </li>
+
+  <li>Click the checkbox next to <strong>Include my app in Google Play for
+  Education...</strong>
+  </li>
+
+  <li>In the first dialog that appears, review the content policies and
+  guidelines and click <strong>Continue</strong> if your app meets the the
+  policies and guidelines.
+  </li>
+
+  <li>In the next dialog that appears, shown below, find the
+  <strong>Ads</strong> and <strong>In-app purchases</strong> radio buttons.
+  Check each option that applies. Your app's use of ads or in-app purchases
+  will be shown to educators when they are browsing your app.
+  </li>
+
+  <li>Click <strong>Save</strong>f to save your Pricing and Distribution
+  changes.
+  </li>
 </ol>
 
 <div style="clear:both;margin-top:1.5em;margin-bottom:1.5em;width:660px;">
-<img src="{@docRoot}images/gp-edu-ads-iab.png" style="border:2px solid #ddd;width:660px;" />
-<p class="image-caption"><span style="font-weight:500;">Ads and in-app purchase</span>:
-When you opt-in to Google Play for Education, make sure to declare your app's use of ads and
-in-app purchases.</p>
+  <img src="{@docRoot}images/gp-edu-ads-iab.png" style=
+  "border:2px solid #ddd;width:660px;">
+  <p class="img-caption">
+    <strong>Ads and in-app purchase</strong>: When you opt-in to Google Play
+    for Education, make sure to declare your app's use of ads and in-app
+    purchases.
+  </p>
 </div>
 
-<p>Once you save changes and publish your app, the app will be submitted to our
-third-party educator network for review and approval. If the app is already
-published, it will be submitted for review as soon as you opt-in and save your
-changes. </p>
+<p>
+  Once you save changes and publish your app, the app will be submitted to our
+  third-party educator network for review and approval. If the app is already
+  published, it will be submitted for review as soon as you opt-in and save
+  your changes.
+</p>
 
-<p class="note"><strong>Note</strong>: Google Play for Education is part of
-Google Play. When you publish an app that's opted-in to Google Play for
-Education, the app becomes available to users in Google Play right away. After
-the app is reviewed and approved, it then becomes available to educators in
-Google Play for Education.</p>
+<p class="note">
+  <strong>Note</strong>: Google Play for Education is part of Google Play. When
+  you publish an app that's opted-in to Google Play for Education, the app
+  becomes available to users in Google Play right away. After the app is
+  <a href="{@docRoot}distribute/essentials/gpfe-guidelines.html#e-value">review
+  and approval</a>, it then becomes available to educators in Google Play for
+  Education.
+</p>
 
-<h3 id="review">4. Track your review and approval</h3>
+<h3>
+  Track your review and approval
+</h3>
 
-<p>Google Play for Education provides content to educators in a way that's
-properly organized by subject, grade level, and common core standards (where
-applicable). To ensure high educational value and proper classification, we work
-with a third-party educator network to review and approve apps before making
-them discoverable through the Google Play for Education browsing tools. </p>
+<p>
+  As soon as you opt-in to Google Play for Education and publish, your apps are
+  queued for review by our third-party educator network. The review and
+  approval process can take four weeks or more. You'll receive notification by
+  email (to your developer account address) when the review is complete, with a
+  summary of the review results.
+</p>
 
-<p>Our third-party educator network will evaluate apps according to educational
-value and alignment with K-12 core standards, then assign the metadata for
-subject, grade level, and core curriculum that makes them easily browsable for
-educators. To understand how your apps will be evaluated, please see the <a
-href="{@docRoot}distribute/googleplay/edu/guidelines.html">Guidelines for
-Apps</a> document.</p>
-
-<p>As soon as you opt-in to Google Play for Education and publish, your app is
-queued for review by our third-party educator network. The review and approval
-process can take four weeks or more</strong>. You'll receive notification
-by email (to your developer account address) when the review is complete, with a
-summary of the review results. </p>
-
-<p>At any time, you can check the review and approval status of your app in the
-<a href="https://play.google.com/apps/publish/">Developer Console</a>, under
-"Google Play for Education" in the app's Pricing and
-Distribution page. There are three approval states:</p>
+<p>
+  At any time, you can check the review and approval status of your app in the
+  Developer Console, under "Google Play for Education" in the app's Pricing and
+  Distribution page. There are three approval states:
+</p>
 
 <ul>
-<li><em>Pending</em> &mdash; Your app was sent for review and the review
-is not yet complete.</li>
-<li><em>Approved</em> &mdash; Your app was reviewed and approved. The app
-will be made available directly to educators through Google Play for Education.
-Once your app is approved, you can update it at your convenience without needing
-another full review. </li>
-<li><em>Not approved</em> &mdash; Your app was reviewed and not approved.
-Check the notification email for information about why the app was not approved.
-You can address any issues and opt-in again for another review. </li>
+  <li>
+    <em>Pending</em> &mdash; Your app was sent for review and the review isn't
+    yet complete.
+  </li>
+
+  <li>
+    <em>Approved</em> &mdash; Your app was reviewed and approved. The app will
+    be made available directly to educators through Google Play for Education.
+    Once your app is approved, you can update it at your convenience without
+    needing another full review.
+  </li>
+
+  <li>
+    <em>Not approved</em> &mdash; Your app was reviewed and not approved. Check
+    the notification email send for information about why the app wasn’t
+    approved. You can address any issues and opt-in again for another review.
+  </li>
 </ul>
+<div class="headerLine">
+<h1 id="related-resources">Related Resources</h1><hr>
+</div>
 
-<p>If you have questions about the review status of your app, follow the process
-discussed in the next section. </p>
+<div class="dynamic-grid">
+<h3>FOR DEVELOPERS</h3>
 
-<h3 id="appeal">5. Get support or appeal your review results</h3>
+<div class="resource-widget resource-flow-layout col-13"
+    data-query="collection:distribute/googleplay/gpfe/dev"
+    data-sortOrder="-timestamp"
+    data-cardSizes="9x3,9x3,6x3,6x3,6x3"
+    data-maxResults="8"></div>
 
-<p>After your app is reviewed you'll receive an email giving you the
-results, including information on whether the app was approved and
-what issues may need to be addressed. You'll receive the email at the address
-you specified for your developer account. </p>
+<h3>FOR EDUCATORS</h3>
 
-<p>If your app has issues that need to be addressed, make the necessary
-adjustments, upload your app, and then resubmit the app to Google Play for
-Education through the Developer Console using process described above. Your app
-will be queued for review and you'll receive the review results by email just
-as before.</p>
-
+<div class="resource-widget resource-flow-layout col-13"
+    data-query="collection:distribute/googleplay/aboutgpfe/educators"
+    data-sortOrder="-timestamp"
+    data-cardSizes="9x3"
+    data-maxResults="3"></div>
+</div>
\ No newline at end of file
diff --git a/docs/html/distribute/googleplay/googleplay_toc.cs b/docs/html/distribute/googleplay/googleplay_toc.cs
new file mode 100644
index 0000000..4196c39
--- /dev/null
+++ b/docs/html/distribute/googleplay/googleplay_toc.cs
@@ -0,0 +1,47 @@
+<ul id="nav">
+
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/googleplay/about.html">
+            <span class="en">The Google Play Opportunity</span></a>
+    </div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/googleplay/start.html">
+            <span class="en">Get Started with Publishing</span>
+          </a>
+    </div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/googleplay/developer-console.html">
+          <span class="en">Developer Console</span>
+        </a>
+    </div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/googleplay/edu/about.html">
+          <span class="en">Google Play for Education</span>
+        </a>
+    </div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/googleplay/edu/start.html">
+          <span class="en">Get Started with Education</span>
+        </a>
+    </div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/googleplay/edu/faq.html">
+          <span class="en">Education FAQ</span>
+        </a>
+    </div>
+  </li>
+</ul>
+
+
+<script type="text/javascript">
+<!--
+    buildToggleLists();
+    changeNavLang(getLangPref());
+//-->
+</script>
+
diff --git a/docs/html/distribute/googleplay/index.jd b/docs/html/distribute/googleplay/index.jd
new file mode 100644
index 0000000..a215930
--- /dev/null
+++ b/docs/html/distribute/googleplay/index.jd
@@ -0,0 +1,45 @@
+page.title=Google Play
+section.landing=true
+nonavpage=true
+
+@jd:body
+
+ <p>
+  The premier store for distributing Android apps and games, with global reach
+  and <span style="white-space:nowrap;">tools to
+  help you gain traction in the marketplace.</span>
+</p>
+
+<div class="dynamic-grid">
+
+  <h3>Overview</h3>
+
+  <div class="resource-widget resource-flow-layout landing col-16"
+    data-query="collection:distribute/gp/gplanding"
+    data-sortOrder="-timestamp"
+    data-cardSizes="6x6"
+    data-maxResults="3">
+  </div>
+
+  <h3>Google Play for Education</h3>
+
+  <div class="resource-widget resource-flow-layout landing col-16"
+    data-query="collection:distribute/gp/gpfelanding"
+    data-cardSizes="6x6"
+    data-maxResults="3">
+  </div>
+
+  <h3>Related resources</h3>
+
+  <div class="resource-widget resource-flow-layout col-16"
+    data-query="type:youtube+tag:growth"
+    data-cardSizes="6x3"
+    data-maxResults="3">
+  </div>
+  <div class="resource-widget resource-flow-layout col-16"
+    data-query="type:blog+tag:googleplay"
+    data-cardSizes="6x3"
+    data-maxResults="3">
+  </div>
+
+</div>
diff --git a/docs/html/distribute/googleplay/policies/ads.jd b/docs/html/distribute/googleplay/policies/ads.jd
deleted file mode 100644
index f2fb0f8..0000000
--- a/docs/html/distribute/googleplay/policies/ads.jd
+++ /dev/null
@@ -1,350 +0,0 @@
-page.title=Ads
-@jd:body
-
-<div id="qv-wrapper">
-<div id="qv">
-  <h2>In This Document</h2>
-  <ol>
-    <li><a href="#content-maturity">Content and Maturity</a></li>
-    <li><a href="#context">Context and Behavior</a></li>
-    <li><a href="#disclosure" style="clear:right">Disclosure</a></li>
-    <li><a href="#impersonation">Impersonation of System UI</a></li>
-    <li><a href="#adwalls">Adwalls and Interstitial Ads</a></li>
-    <li><a href="#interfering" style="clear:right;">Interference with Apps and Third-Party Ads</a></li>
-  </ol>
-
-  <h2>More Resources</h2>
-  <ol>
-    <li><a href="http://play.google.com/about/developer-content-policy.html" target="_policies">Developer Program Policies</a></li>
-    <li><a href="http://www.android.com/us/developer-distribution-agreement.html#showlanguages" target="_policies">Developer Distribution Agreement</a></li>
-    <li><a href="http://support.google.com/googleplay/android-developer/answer/188189" target="_policies">Maturity Ratings</a></p>
-  </ol>
-</div>
-</div>
-
-<p>
-  Google Play policies guide how you can use ads in your apps, to help ensure
-  the best experience for users visiting and downloading apps from the store.
-</p>
-
-<p>
-  In general, for the purposes of policy, the content of ads displayed by your
-  app is considered part of your app. As an app developer, it is your
-  responsibility to ensure that the content, context, and behavior of ads in
-  your apps conforms to Google Play policies.
-</p>
-
-<p>
-  Before you publish, make sure you understand Google Play ad policies and how
-  to display ads in conformance with those policies. The sections below
-  highlight best practices and common examples to help you avoid the most
-  common types of policy violations.
-</p>
-
-<p>
-  For more information about Google Play policies that apply to your apps and
-  content, please see the <a href=
-  "http://play.google.com/about/developer-content-policy.html" target=
-  "_policies">Developer Program Policies</a> and <a href=
-  "http://play.google.com/about/developer-distribution-agreement.html" target=
-  "_policies">Developer Distribution Agreement</a>.
-</p>
-
-
-<h2 id="content-maturity">Content and Maturity</h2>
-
-<div class="example-block bad">
-  <div class="heading">Ad maturity exceeds app</div>
-  <img src="{@docRoot}images/gp-policy-ads-maturity-violation.png">
-</div>
-
-<p>
-  From a policy perspective, ads shown in your app are part of your content
-  and your app is responsible for any violations. If an ad shown in your app
-  violates Google Play policies, your app may be suspended or your developer
-  account terminated.
-</p>
-
-<p>
-  For this reason, it's important for you to be be aware of what ads will be
-  displayed in your app and to manage the ads content according to Google Play
-  policies. Here are some guidelines:
-</p>
-
-<ul>
-    <li>
-        <strong>Ads must not violate Content Policy</strong>&mdash;Ads in
-        your app must not violate the terms of Google Play’s Content Policy,
-        including those concerning illegal activities, violence, sexually
-        explicit content, or privacy violations.
-    </li>
-    <li>
-        <strong>Ads maturity must be consistent with your app's
-        maturity</strong>&mdash;Content shown in your ads must be consistent
-        with the app’s maturity rating in Google Play. Especially, ads content
-        should never exceed your app's maturity rating, even if the ads content
-        by itself complies with general policies.
-    </li>
-</ul>
-
-<p>
-  In the example at right, the app's maturity rating is set to
-  "Everyone", which is the lowest maturity level on Google Play. By choosing
-  the "Everyone" maturity level, the developer is declaring that all of the
-  content in the app, <em>including ads</em>, is suitable for all users
-  regardless of age.
-</p>
-
-<p>
-  The example app violates Google Play policies by displaying ad content with a
-  higher maturity level&mdash;ad content showing gambling, profanity, user
-  location, suggestive content, or content from another app with higher
-  maturity exceeds the "Everyone" maturity rating. Because the ad's
-  maturity is higher than the app's maturity level, the app itself is in
-  violation of policy. To correct the problem, the developer must either
-  restrict ads content to "Everyone" level or raise the app's maturity rating.
-</p>
-
-<p>
-  For detailed information about how to choose the appropriate maturity level
-  for your app, or to assess the maturity requirement of ads in your app, see
-  <a href=
-  "http://support.google.com/googleplay/android-developer/answer/188189"
-  target="_policies">Rating your application content for Google Play</a>.
-</p>
-
-
-<h2 id="context">Context and Behavior</h2>
-
-<p>
-  If your app displays ads, it should do so in ways that do not interrupt users,
-  mislead them into clicking on ads, or make changes outside the app without
-  the user's knowledge or consent. Here are some guidelines:
-</p>
-
-<ul>
-  <li>
-    <strong>Display your ads within your UI</strong>&mdash;If possible,
-    display ads only within your app's UI. This leads to a better user
-    experience and helps avoid policy violations
-  </li>
-
-  <li>
-    <strong>Don't make changes outside of the app without consent</strong>
-   &mdash;Ads must not make changes outside of the app without the user's
-    full knowledge and consent.
-  </li>
-
-  <li>
-  <div class="example-block bad" style="width:360px;margin:1em 0 0 2em;">
-    <div class="heading">Ads through system-level notifications</div>
-    <img src="{@docRoot}images/gp-policy-ads-notif-attr-violation.png">
-  </div>
-  <div class="example-block good" style="width:360px;margin:.5em 0 0 2em;">
-    <div class="heading">Notification that's part of the app's feature set</div>
-    <img src="{@docRoot}images/gp-policy-ads-notif-attr.png">
-  </div>
-    <strong>Changes outside the app must be reversible</strong>&mdash;If an
-    ad makes changes outside the app as described above, the changes (and
-    origin app) must be evident and easily reversible. For example, the user
-    must be able to locate and reverse the changes by adjusting settings,
-    changing ad preferences in the app, or uninstalling the app altogether.
-  </li>
-
-  <li>
-    <strong>Notification ads are prohibited</strong>&mdash;Your app
-    should not create system-level <a href=
-    "{@docRoot}design/patterns/notifications.html">notifications</a>
-    containing ads unless the notifications are part of the explicit
-    feature set of the app.
-  </li>
-
-  <li>
-    <strong>Don't add shortcuts, bookmarks, or icons</strong>&mdash;Your app
-    and its ads must not add homescreen shortcuts, browser bookmarks, or icons
-    on the user's device as a service to third parties or for advertising 
-    purposes.
-  </li>
-</ul>
-
-<p>
-  Above right is an example notification ad that violates ad policy by
-  providing ads through system level notification.
-</p>
-<p>
-  Below right, the notification ad complies with policy because the
-  nature of the notification is part of the explicit feature set of the app,
-  and it also provides attribution of the origin app. 
-</p>
-
-<h2 id="disclosure" style="clear:right">Disclosure of Ads to Users</h2>
-
-<p>
-  It's important to sufficiently disclose to users how your app will use ads.
-  You must make it easy for users to understand what ads will be shown in your
-  app, where they will be shown, and what the associated behaviors are, if any.
-  Further, you should ask for user consent and provide options for managing ads
-  or opt-out. Here are some guidelines:
-</p>
-
-<ul>
-  <li>
-    <strong>Tell users about your ads</strong>&mdash;Create a simple,
-    complete disclosure that tells users how your app uses ads, where the ads
-    are shown, and how they can manage ad options. Take common-sense steps to
-    make the disclosure as clear as possible.
-  </li>
-
-  <li>
-    <div class="example-block good" style="width:213px;margin-left:.5em;">
-      <div class="heading">Disclosure in Terms</div>
-      <img src="{@docRoot}images/gp-policy-ads-terms.png">
-    </div>
-    <div class="example-block bad" style="width:213px;">
-      <div class="heading">Disclosure is hidden</div>
-      <img src="{@docRoot}images/gp-policy-ads-eula-violation.png">
-    </div>
-    <strong>Make sure users know</strong>&mdash;Present your ads disclosure
-    is an easy-to-see location, rather than hiding it where users are not
-    likely to find it.
-  </li>
-
-  <li>
-    <strong>Ask for consent (opt-in) at launch</strong>&mdash;Where possible,
-    include your ads disclosure in the app description as well as in an Ads
-    Terms, End User License Agreement (EULA), or similar document. Display the
-    terms at first launch and ask for the user's consent before continuing to
-    the app.
-  </li>
-</ul>
-
-<p>
-  A recommended approach is to provide an ads disclosure in an End-User License
-  Agreement (EULA). The disclosure should be clear and succinct and displayed
-  in a modal dialog that asks the user to agree to the terms before using the
-  app.
-</p>
-
-<p>
-  Above left is an example of ads disclosure that is hidden in a long EULA. The
-  disclosure information itself is not clearly indicated in the document text
-  and it's not visible unless the user happens to scroll down far enough in the
-  EULA. 
-</p>
-<p>
-  Above right shows an approach that presents the disclosure in an obvious
-  and clear manner in a EULA and a dedicated Terms agreement. 
-</p>
-
-
-<h2 id="impersonation">Impersonation of System UI</h2>
-
-
-
-
-
-
-
-
-<p>
-  Ads must not simulate or impersonate the user interface of any app, or
-  notification and warning elements of an operating system. Your app must not
-  display any ad that attempts to impersonate or represent a
-  system function or UI component. If such an ad is displayed in your app, your
-  app will be in violation of policy and subject to suspension. Here are some
-  guidelines:
-</p>
-
-<ul>  
-  <li>
-    <strong>No fake app UI notifications</strong>&mdash;Ads should not impersonate
-    the interface of an application for advertising purposes.
-  </li>
-  <li>
-    <strong>No fake system dialogs or warnings</strong>&mdash;Any ad that
-    presents itself as a system dialog or warning and asks for user input is in
-    violation of Google Play policies.
-  </li>
-
-  <li>
-    <strong>No fake app updates</strong>&mdash;Ads should not impersonate
-    system UI for app updates.
-  </li>
-</ul>
-
-<div class="example-block bad" style="width:213px;">
-  <div class="heading">Ad impersonates app UI</div>
-  <img src="{@docRoot}images/gp-policy-ads-impersonate-violation-app-ui.png">
-</div>
-<div class="example-block bad" style="width:213px;">
-  <div class="heading">Ad impersonates system warning</div>
-  <img src="{@docRoot}images/gp-policy-ads-impersonate-violation-sys-warning.png">
-</div>
-<div class="example-block bad" style="width:213px;">
-  <div class="heading">Ad impersonates system dialog</div>
-  <img src="{@docRoot}images/gp-policy-ads-impersonate-violation.png">
-</div>
-<p style="clear:both">
-  Above are examples of impersonations &mdash; a pop-up ad that impersonates a
-  system dialog, an ad that impersonates a system warning, and an ad that impersonates
-  an application UI. All of these are in violation of policy.
-</p>
-
-
-<h2 id="adwalls">Adwalls and Interstitial Ads</h2>
-
-<p>
-  If your app uses adwalls to drive affiliate traffic, those adwalls must not
-  force the user to click on ads or submit personal information for advertising
-  purposes before using the app.
-</p>
-
-<p>
-  Forcing a user action in an adwall is not only a poor user experience, it is
-  a violation of Google Play policies.
-</p>
-
-<p>
-  For this reason, <strong>all adwalls must give the user the option to
-  cancel</strong> or otherwise dismiss the ad without penalty. Interstitial ads
-  may only be displayed inside of the app they came with. Forcing the user to
-  click on ads or submit personal information for advertising purposes in order
-  to fully use an app is prohibited.
-</p>
-
-<div class="example-block bad" style="width:213px;">
-  <div class="heading">Interstitial, modal ad</div>
-  <img src="{@docRoot}images/gp-policy-ads-interstitial-violation.png">
-</div>
-
-<div class="example-block good" style="width:213px;">
-  <div class="heading">Adwall lets user cancel</div>
-  <img src="{@docRoot}images/gp-policy-ads-paywall.png">
-</div>
-
-<div class="example-block bad" style="width:213px;">
-  <div class="heading">Adwall forces user action</div>
-  <img src="{@docRoot}images/gp-policy-ads-paywall-violation.png">
-</div>
-
-<p style="clear:both">
-  At left is an example of an app that requires the user to click through the
-  ad to fully use the app. This is a violation of policy.
-</p>
-
-<p>
-  The center example demonstrates an adequate option to let the user dismiss
-  the ad wall easily by cancelling. This is not a violation of policy.
-</p>
-
-<p>
-  At right is an example of an interstitial, modal ad that is displayed outside
-  of the app. This is a violation of policy.
-</p>
-
-<h2 id="interfering" style="clear:right;">Interfering with Apps and Third-Party Ads</h2>
-
-<p>
-  Ads associated with your app <strong>must not interfere</strong> with other
-  apps or their ads.
-</p>
\ No newline at end of file
diff --git a/docs/html/distribute/googleplay/policies/index.jd b/docs/html/distribute/googleplay/policies/index.jd
deleted file mode 100644
index fb46055..0000000
--- a/docs/html/distribute/googleplay/policies/index.jd
+++ /dev/null
@@ -1,59 +0,0 @@
-page.title=Google Play Policies and Guidelines
-page.metaDescription=Guidelines and tips for creating apps that comply with Google Play content and distribution policies.
-@jd:body
-
-<p>
-  Before publishing your apps on Google Play, take a few minutes to read and
-  understand the content and distribution policies that apply to all apps
-  in the store. These policies help to keep Android and Google Play an enjoyable
-  and trusted platform for content consumers and developers alike.
-</p>
-
-<p>
-  The documents below highlight important policy areas and provide tips to help
-  you create policy-compliant apps. You'll also find examples and guidance on common
-  policy questions that can help your app stay clear of practices that can result in
-  low ratings or even suspensions from the store.
-</p>
-
-<p>
-  For complete information about Google Play policies, please see the full
-  <a href="http://play.google.com/about/developer-content-policy.html" target=
-  "_policies">Developer Program Policies</a> and <a href=
-  "http://play.google.com/about/developer-distribution-agreement.html" target=
-  "_policies">Developer Distribution Agreement</a> documents.
-</p>
-
-<div class="vspace size-1">
-  &nbsp;
-</div>
-<div class="layout-content-row">
-  <div class="layout-content-col span-4">
-    <h4>
-      Spam
-    </h4>
-    <p>
-      Make sure that your app does not present content that is unwanted,
-      deceptive, repetitive, or unrelated to the core function of the app.
-    </p><a href="{@docRoot}distribute/googleplay/policies/spam.html">Learn more &raquo;</a>
-  </div>
-  <div class="layout-content-col span-4">
-    <h4>
-      Intellectual Property
-    </h4>
-    <p>
-      Tips and examples of how to use intelletual property (IP) properly,
-      including when to ask permission to use someone else's copyright or
-      trademark.
-    </p><a href="{@docRoot}distribute/googleplay/policies/ip.html">Learn more &raquo;</a>
-  </div>
-  <div class="layout-content-col span-4">
-    <h4>
-      Ads
-    </h4>
-    <p>
-      Make sure that the ads displayed in your app follow the Google Play Content
-      Policy and meet the maturity rating that you have selected for your app.
-    </p><a href="{@docRoot}distribute/googleplay/policies/ads.html">Learn more &raquo;</a>
-  </div>
-</div>
\ No newline at end of file
diff --git a/docs/html/distribute/googleplay/policies/ip.jd b/docs/html/distribute/googleplay/policies/ip.jd
deleted file mode 100644
index 0d1f68d..0000000
--- a/docs/html/distribute/googleplay/policies/ip.jd
+++ /dev/null
@@ -1,345 +0,0 @@
-page.title=Intellectual Property
-@jd:body
-
-<div id="qv-wrapper">
-<div id="qv">
-  <h2>In This Document</h2>
-  <ol>
-    <li><a href="#copyright">Copyright Infringement</a></li>
-    <li><a href="#impersonation">Impersonation</a></li>
-    <li><a href="#trademarks">Trademark Infringement</a></li>
-    <li><a href="#other">DDA 4.4 Prohibited Actions</a></li>
-  </ol>
-
-  <h2>More Resources</h2>
-  <ol>
-    <li><a href="http://play.google.com/about/developer-content-policy.html"
-    target="_policies">Developer Program Policies</a></li>
-    <li><a href="http://www.android.com/us/developer-distribution-agreement.html#showlanguages"
-    target="_policies">Developer Distribution Agreement</a></li>
-  </ol>
-</div>
-</div>
-
-<p>
-  Google Play policies protect your intellectual property (IP) as well as that
-  of other app developers and content creators in the store. The policies and
-  their enforcements help ensure proper use of copyright, trademarks, and
-  developer identity in Google Play.
-</p>
-
-<p>
-  As an app developer, these IP policies benefit you. At the same time, it's
-  your responsibility to ensure that your app does not violate the IP of other
-  developers or content creators. Violations of IP-related policy may result in
-  suspension of your apps from the store and termination of your developer
-  account.
-</p>
-
-<p>
-  This document introduces several key areas of IP-related policy that you
-  should understand before publishing on Google Play. In each area you'll find
-  best practices and examples to help you avoid common types of mistakes and
-  violations.
-</p>
-
-<p>
-  For more information about Google Play policies that apply to your apps and
-  content, please see the <a href=
-  "http://play.google.com/about/developer-content-policy.html" target=
-  "_policies">Developer Program Policies</a> and <a href=
-  "http://play.google.com/about/developer-distribution-agreement.html" target=
-  "_policies">Developer Distribution Agreement</a>.
-</p>
-
-
-
-<h2 id="copyright">Copyright Infringement</h2>
-
-<p>
-  Copyright is the legal right granted to an author or creator for a literary,
-  dramatic or artistic piece of work. As soon as you create an original piece
-  of work and fix it in a tangible medium, the work is automatically protected
-  by copyright law and you are the owner of the copyright. Likewise, when other
-  people create content, they may own the copyrights for those works.
-</p>
-
-
-<div class="sidebox-wrapper">
-<div class="sidebox">
-<h2>How to report infringements</h2>
-<p>If you feel your copyright is being infringed, you may file a Digital Millenium
-   Copyright Act (DMCA) request. Please see <a 
-   href="http://support.google.com/bin/request.py?&product=androidmarket&contact_type=lr_dmca"
-   target="_policies">copyright procedures</a> for more information.</p>
-</div>
-</div>
-
-<p>
-  Copyright infringement is an improper or unauthorized use of a copyrighted
-  work. If you publish an app in Google Play that uses another party's copyrighted
-  works improperly or without permission, your apps can be suspended and your
-  developer account terminated.
-</p>
-
-<p>
-  As you design your app and prepare for publishing, make sure to review Google
-  Play policies and analyze all of your content. If your app uses or links to
-  another party's original work, make sure that your app is not infringing on
-  copyright. Not all uses of another party’s work are infringements on
-  copyright, and the rules vary by country and can be complex.
-</p>
-
-<p>
-  If you are unsure whether your use of another party's work infringes on a
-  copyright, consider getting legal advice before publishing, or simply request
-  permission to use the work from the copyright owner.
-</p>
-
-<p>
-  Here are some guidelines to help you avoid copyright infringement policy
-  violations:
-</p>
-
-<ul>
-  <li>
-    <strong>Respect copyright laws</strong>&mdash;Do not let your app infringe
-    on the copyrights of others. That includes linking to other apps or web
-    sites that contain obviously infringing material (please refer to the <a href="
-    {@docRoot}distribute/googleplay/policies/spam.html#webview-spam">Spam in WebViews</a> guidelines), and using icons or images that are obvious infringements.
-  </li>
-
-  <li>
-    <strong>Know your app's content</strong>&mdash;Before you publish, look
-    for content that may be protected by trademark or copyright in your app
-    and get legal advice if necessary. Protected work could typically include
-    product names, brands, images, music, and similar works.
-  </li>
-
-  <li>
-    <strong>Create original work</strong>&mdash;If you’re not sure whether
-    something will violate another party's copyright, the safest approach is to
-    create something that's completely original, such as images or audio
-    that you’ve created yourself. When you create your own original content,
-    you rarely have to worry about infringing on existing copyright.
-  </li>
-
-  <li>
-    <strong>Ask permission to use copyrighted work</strong>&mdash;If you want
-    to use another party's copyrighted work in your app, you should ask for
-    permission from the work's creator or copyright owner and include
-    appropriate copyright attribution.
-  </li>
-</ul>
-
-<p>
-  A common misunderstanding is believing that your app may use copyrighted
-  content without permission, provided that you clearly indicate that your app
-  is not the "official" app that readers may be familiar with. That is not the
-  case. Even if you let users know that your app is "unofficial", it still
-  violates Google Play policies if it uses or links to copyrighted content
-  without permission. Also, this type of "unofficial" app may violate <a
-  href="#impersonation">impersonation policies</a>.
-</p>
-
-<p>
-  The example app below shows an app that uses screenshots/images of known
-  artists without their authorization and lists popular songs. The combination
-  of these may induce users to download music ringtones that infringe on
-  copyright. This is a violation of Google Play policy.
-</p>
-
-<div class="example-block bad" style="width:100%;float:none;margin:.5em auto 2em 0;">
-  <div class="heading">Images and downloads that violate copyright</div>
-  <img src="{@docRoot}images/gp-policy-ip-copyright-violation.png">
-</div>
-
-
-<h2 id="impersonation">Impersonation</h2>
-
-<p>
-  Impersonation is when an app attempts to imply a relationship to another app
-  or developer, where no relationship actually exists.
-</p>
-
-<p>
-  For example, if your app displays the brand, icon, or title from another app
-  in order to get to users to download your app, you are leading users to
-  believe that your app is developed by the same entity as the other app and
-  offers similar content or experience. This is an impersonation of the other
-  app and developer, and it is a violation of Google Play policy. If you
-  publish apps that violate impersonation policies, your apps can be suspended
-  and your developer account terminated.
-</p>
-
-<p>
-  No matter what type of app you offer or what your motivation, don’t try to
-  imply an endorsement or relationship to another company or product where none
-  exists. Don’t try to establish your app as the "official" version of another
-  party's work by prominently featuring their brand names or trademarks in your
-  app title or description.
-</p>
-
-<p>
-  Even if your app description states that your app is an "unofficial" version,
-  the use of the other app's branding, trademarks, and other content still can
-  violate policy by presenting content that isn’t yours.
-</p>
-
-<p>
-  Here are some guidelines:
-</p>
-
-<ul>
-  <li>
-    <strong>Don't pretend to be someone else</strong>&mdash; Don't represent
-    that your content is produced by another company or organization if that is
-    not the case.
-  </li>
-
-  <li>
-    <strong>Don't support infringing sites or apps</strong>&mdash; Don't divert
-    users or provide links to any other site that mimics Google Play or
-    represents itself as another application or service.
-  </li>
-
-  <li>
-    <strong>Don't use another app's branding</strong>&mdash; Don’t try to pass
-    off your app as the official version of someone else’s property by using a
-    person or entity (or brand) name in your app title or description.
-  </li>
-</ul>
-
-<p>
-  Below is an example of an "unofficial" app that violates Google Play policy
-  by impersonating another company and an existing product. Specifically:
-</p>
-
-<ul>
-  <li>The example app has a name and icon that appear to be impersonating an
-  existing product.
-  </li>
-
-  <li>The example developer name implies an endorsement or relationship to
-  another company and their products where none exists.
-  </li>
-</ul>
-
-<div class="example-block bad" style="width:100%;float:none;margin:.5em auto 2em 0;">
-  <div class="heading">App name, icon, and developer name that impersonate another</div>
-  <img src="{@docRoot}images/gp-policy-ip-impersonation-violation.png">
-</div>
-
-
-<h2 id="trademarks">Trademark Infringement</h2>
-
-<p>
-  A trademark is a brand that uniquely identifies a product and distinguishes
-  it from other products. It can be a word, name, symbol, or combination of
-  those that is intended to identify the source of the product. A trademark is
-  specifically acquired by a company or other entity through a legal process
-  and once acquired gives the owner exclusive rights to the trademark usage.
-</p>
-
-<div class="sidebox-wrapper">
-<div class="sidebox">
-<h2>How to report infringements</h2>
-<p>If you feel your trademark is being infringed, you can request a content review.
-See <a href="http://support.google.com/bin/static.py?&ts=1114905&page=ts.cs"
-target="_policies">Removing content from Google</a> for more information.</p>
-</div>
-</div>
-
-<p>
-  Trademark infringement is improper or unauthorized use of a trademark. Google
-  Play policies prohibit apps that infringe trademarks. If you publish apps in
-  Google Play that use another party's trademarks, your apps can be suspended
-  and your developer account terminated.
-</p>
-
-<p>
-  As you design your app and prepare for publishing, make sure to review Google
-  Play policies and analyze all of your content. If your app uses a trademark
-  not owned by you, or if you are not sure whether a brand is a trademark, you
-  should get legal advice before publishing. As with copyright, the rules vary
-  by country and can be complex.
-</p>
-
-<p>
-  Here are some guidelines for avoiding trademark infringement policy
-  violations:
-</p>
-
-<ul>
-  <li>
-    <strong>Understand and follow trademark laws</strong>&mdash;Don't let your
-    app infringe on the trademarks of others.
-  </li>
-
-  <li>
-    <strong>Know your app's content</strong>&mdash;Before you publish, look for
-    brands and potential trademarks used in your app and store listing and get
-    legal advice if necessary.
-  </li>
-
-  <li>
-    <strong>Use a distinct name</strong>&mdash;Don't give your app a name that
-    is confusingly similar to another company's trademark.
-  </li>
-
-  <li>
-    <strong>Don't use trademarks to imply a relationship</strong>&mdash;Don't
-    describe your app using another company's trademarks in a way that implies
-    an endorsement by or affiliation with the other company.
-  </li>
-
-  <li>
-    <strong>Use a distinct app icon and logo</strong>&mdash;Don't use a
-    modified version of another company’s trademarked logo.
-  </li>
-</ul>
-
-<p>
-  A common misunderstanding is believing that your app may use a brand or
-  trademark without permission, provided you clearly indicate that the app is
-  not the "official" or original app. That is not the case. Even if you let
-  users know that your app is "unofficial", it still violates Google Play
-  policies if it uses another party's trademarks. Also, this type of
-  "unofficial" app may violate <a href="#impersonation">impersonation
-  policies</a>.
-</p>
-
-<p>
-  Below is an example app that violates Google Play policies by infringing on
-  another party's trademarks. Specifically:
-</p>
-
-<ul>
-  <li>The example app name is confusingly similar to another party's trademark.</li>
-  <li>The example app icon is a modified version of a another party's logo.</li>
-</ul>
-
-<div class="example-block bad" style="width:100%;float:none;margin:.5em auto 2em 0;">
-  <div class="heading">App name and icon that infringe trademarks</div>
-  <img src="{@docRoot}images/gp-policy-ip-trademark-violation.png">
-</div>
-
-
-<h2 id="other">DDA 4.4 Prohibited Actions</h2>
-
-<p>
-  When you publish an app on Google Play, you agree to the terms of the
-  Developer Distribution Agreement (DDA). Section 4.4 of the DDA prohibits certain
-  types of actions on your part. For reference, you agree that you will not
-  engage in any activity with the Market, including the development or
-  distribution of Products, that interferes with, disrupts, damages, or
-  accesses in an unauthorized manner the devices, servers, networks, or other
-  properties or services of any third party including, but not limited to,
-  Android users, Google or any mobile network operator.
-</p>
-
-<p>
-  For details, please refer to the complete <a href=
-  "http://play.google.com/about/developer-distribution-agreement.html" target=
-  "_policies">Developer Distribution Agreement</a>.
-</p>
\ No newline at end of file
diff --git a/docs/html/distribute/googleplay/policies/spam.jd b/docs/html/distribute/googleplay/policies/spam.jd
deleted file mode 100644
index f4d303c..0000000
--- a/docs/html/distribute/googleplay/policies/spam.jd
+++ /dev/null
@@ -1,421 +0,0 @@
-page.title=Spam
-@jd:body
-
-<div id="qv-wrapper">
-<div id="qv">
-  <h2>In This Document</h2>
-  <ol>
-    <li><a href="#keyword-spam">Spam in App Title and Description</a></li>
-    <li><a href="#ratings">Spam in Ratings and Reviews</a></li>
-    <li><a href="#webview-spam">Spam in WebViews</a></li>
-    <li><a href="#wizard-spam">Spam from Wizards</a></li> 
-    <li><a href="#message-spam">Spam in Messaging</a></li>
-  </ol>
-
-  <h2>More Resources</h2>
-  <ol>
-    <li><a href="http://play.google.com/about/developer-content-policy.html" target="_policies">Developer Program Policies</a></li>
-    <li><a href="http://play.google.com/about/developer-distribution-agreement.html" target="_policies">Developer Distribution Agreement</a></li>
-  </ol>
-</div>
-</div>
-
-<p>
-  Google Play policies prohibit spam, to help ensure the best experience for
-  Android users. Please do not publish deceptive, repetitive, or irrelevant
-  content on Google Play. Not only will it lower your app's rating and cause
-  negative reviews, it can result in your app being suspended or your developer
-  account terminated.
-</p>
-
-<p>
-  As an app developer, it is your responsibility to ensure that your apps are
-  free from spam and conform to the Google Play policies highlighted in this
-  document. Before you publish, make sure that you understand what is
-  considered spam on Google Play and check your apps for violations, even those
-  that might be inadvertent. The sections below highlight best practices and
-  common spam examples to help you avoid the most common types of policy
-  violations.
-</p>
-
-<p>
-  For more information about Google Play policies that apply to your apps and
-  content, please see the <a href=
-  "http://play.google.com/about/developer-content-policy.html" target=
-  "_policies">Developer Program Policies</a> and <a href=
-  "http://play.google.com/about/developer-distribution-agreement.html" target=
-  "_policies">Developer Distribution Agreement</a>.
-</p>
-
-
-<h2 id="keyword-spam">Spam in App Title and Description</h2>
-
-<p>
-  When you publish an app on Google Play, you should pay special attention to
-  the app's title and description in its store listing. Those fields are
-  important because they make your app recognizable to users, and they help to
-  drive downloads by highlighting what's great about your app. A memorable
-  title and compelling description are essential to effective marketing, but
-  you should realize that these must follow Google Play policies, just as your
-  app content must do.
-</p>
-
-<p>
-  Many developers unknowingly violate spam policy in their app titles and
-  descriptions in ways that are easy to avoid. In general, you can
-  avoid spam violations in your app title and description by following these
-  best practices:
-</p>
-
-<ul>
-  <li>
-    <strong>Highlight what's great about your app</strong>&mdash;Share
-    interesting and exciting facts about your app with users. Help users
-    understand what makes your app special.
-  </li>
-
-  <li>
-    <strong>Describe your app accurately</strong>&mdash;Make sure the title
-    and description describe the app function and user experience accurately.
-  </li>
-
-  <li>
-    <strong>Don't use repetitive keywords</strong>&mdash;Avoid keywords that
-    are repetitive or excessive.
-  </li>
-
-  <li>
-    <strong>Don't include unrelated keywords or references</strong> &mdash;
-    Your description should not be loaded with irrelevant keywords in an
-    attempt to manipulate ranking or relevancy.
-  </li>
-
-  <li>
-    <strong>Keep it brief</strong>&mdash;Keep the description succinct and
-    straightforward. Shorter descriptions tend to give a better user experience
-    on devices with smaller displays. Excessive length, detail, or repetition
-    can violate spam policy.
-  </li>
-</ul>
-
-<p>
-  Here's an example app title and description that follows best practices and
-  does not violate Google Play spam policies.
-</p>
-
-<div class="example-block good" style="width:100%;float:none;margin:.5em auto 2em 0;">
-  <div class="heading">Best practice: App description</div>
-  <table>
-  <tr>
-    <td>App Title:</td>
-    <td>Kids puzzle: Identify Turtles</td>
-  </tr>
-  <tr>
-    <td style="white-space:nowrap;">App Description:</td>
-    <td>
-      <p>This is the perfect app to have a good time with your children. It
-        is designed to help kids learn different species of turtles through
-        cute pictures and amusing puzzle games.</p>
-      <p>The rules of Kids puzzle: Identify Turtles are quite simple. Have
-        your child drag images around the screen to fit them into the shaded
-        region. Phonics is also utilized, as a child can also tap the word
-        below the image and hear the name pronounced.</p>
-    </td>
-  </tr>
-  </table>
-</div>
-
-<p>
-  The sections below highlight common types of policy violations in an app
-  title and description, illustrated with variations on the best practice
-  example. 
-</p>
-
-<h3 id="repetitive-keywords">Repetitive keywords</h3>
-
-<p>
-  Your app description should not include keywords that are repetitive or excessive.
-</p>
-
-<div class="example-block bad" style="width:100%;float:none;margin:.5em auto 2em 0;">
-  <div class="heading">Description includes repetitive keywords</div>
-  <table>
-  <tr>
-    <td>App Title:</td>
-    <td>Kids puzzle: Identify Turtles</td>
-  </tr>
-  <tr>
-    <td style="white-space:nowrap;">App Description:</td>
-    <td>
-      <p>This is the perfect app to have a good time with your children. It is
-        designed to help kids learn different species of turtles through cute
-        pictures and amusing puzzle games.</p>
-      <p>The rules of Kids puzzle: Identify Turtles are quite simple. Have your
-        child drag images around the screen to fit them into the shaded region.
-        Phonics is also utilized, as a child can also tap the word below the image
-        and hear the name pronounced.</p>
-      <p style="border:2px solid red;">KEYWORDS: game, games, fun, funny, child,
-        children, kid, kids, puzzle, puzzle games, sound, turtle, turtles, sea turtles,
-        turtles, turtle, turtles, tortoise, tortoises, tortoise, tortoise,  turtles,
-        turtles, turtles, turtles, tortoises, tortoise</p>
-    </td>
-  </tr>
-  </table>
-</div>
-
-<h3 id="unrelated-keywords">Unrelated keywords or references</h3>
-
-<p>
-  The description should not be loaded with irrelevant keywords in an attempt
-  to manipulate ranking or relevancy in Google Play search results.
-</p>
-
-<p>
-  For example, if your app has nothing to do with Lady Gaga, then she shouldn’t
-  be included in your description. Also, do not add highly searched, irrelevant
-  keywords that are unrelated to the function of the app. This is in breach of
-  policy.
-</p>
-
-<div class="example-block bad" style="width:100%;float:none;margin:.5em auto 2em 0;">
-  <div class="heading">Description includes unrelated keywords or references</div>
-  <table>
-  <tr>
-    <td>App Title:</td>
-    <td>Kids puzzle: Identify Turtles</td>
-  </tr>
-  <tr>
-    <td style="white-space:nowrap;">App Description:</td>
-    <td>
-      <p>This is the perfect app to have a good time with your children. It is designed to
-        help kids learn different species of turtles through cute pictures and amusing puzzle
-        games.</p>
-      <p>The rules of Kids puzzle: Identify Turtles are quite simple. Have your child drag
-        images around the screen to fit them into the shaded region. Phonics is also utilized,
-        as a child can also tap the word below the image and hear the name pronounced.</p>
-      <p style="border:2px solid red;">This game is as addictive as Angry Birds, more social
-        than Facebook and Twitter, and has a soundtrack reminiscent of Katy Perry and Lady
-        Gaga.</p>
-      <p style="border:2px solid red;">KEYWORDS: Angry Birds, Facebook, Twitter, Katy Perry,
-        Lady Gaga</p>
-    </td>
-  </tr>
-  </table>
-</div>
-
-<h3 id="excessive-detail">Excessive detail, references to your other apps</h3>
-
-<p>
-  Your app description should avoid excessive detail and references to your
-  other apps or products. For example, you should not list all of the details
-  of content included in the app or its various components, as shown in the
-  example below. Also, the description should not include any references to
-  other apps you’ve published.
-</p>
-
-<div class="example-block bad" style="width:100%;float:none;margin:.5em auto 2em 0;">
-  <div class="heading">Description includes excessive detail, references to your other apps</div>
-  <table>
-  <tr>
-    <td>App Title:</td>
-    <td>Kids puzzle: Identify Turtles</td>
-  </tr>
-  <tr>
-    <td style="white-space:nowrap;">App Description:</td>
-    <td>
-      <p>This is the perfect app to have a good time with your children. It is designed
-        to help kids learn different species of turtles through cute pictures and amusing
-        puzzle games.</p>
-      <p>The rules of Kids puzzle: Identify Turtles are quite simple. Have your child
-        drag images around the screen to fit them into the shaded region. Phonics is also
-        utilized, as a child can also tap the word below the image and hear the name
-        pronounced.</p>
-      <p style="border:2px solid red;">Turtles included in the app: Alligator
-        Snapping Turtle, Asian Box Turtle, Bog Turtle, Common Musk Turtle, Common Snapping
-        Turtle, Diamondback Terrapin, Eastern Box Turtle, Eastern Mud Turtle, Eastern Painted
-        Turtle, False Map Turtle, Florida Pond Cooter, Florida Softshell Turtle, Green Sea
-        Turtle, Map Turtle, Matamata Ornate Box Turtle, Red-bellied Side-necked Turtle,
-        Red-eared Slider, Smooth Softshell Turtle, Spiny Softshell Turtle, Spotted Turtle,
-        Western Painted Turtle, Wood Turtle, Yellow-bellied Slider</p>
-      <p style="border:2px solid red;">If you like this app try our other free apps:<br />
-       ★ Fun Zoo<br />
-       ★ CD Guns<br />
-       ★ Dessert House<br />
-       ★ Playground<br />
-       ★ 578 Weapons</p>
-    </td>
-  </tr>
-  </table>
-</div>
-
-
-<h2 id="ratings">Spam in Ratings and Reviews</h2>
-
-<div class="example-block bad" style="width:440px;">
-  <div class="heading">Inappropriate content in a review</div>
-  <img src="{@docRoot}images/gp-policy-spam-negreview.png">
-</div>
-
-<p>
-  Ratings and reviews are benchmarks of app quality and users depend on them to
-  be authentic and relevant. As an app developer, you should not attempt to
-  artificially influence your app's ratings and reviews or those of your
-  competitor, such as by posting fake ratings or reviews or including spam
-  content in app reviews. The sections below provide guidelines for rating and
-  reviewing apps.
-</p>
-
-<p>
-  So that you can stay in touch with any issues that users are having with your
-  app, you should read through your ratings and reviews on a regular basis. If
-  you choose to reply to reviews, make sure to keep your reply focused on the
-  actual issues raised in the user's comments and do not ask for a higher
-  rating.
-</p>
-
-<p>
-  If you see an app or developer reply that doesn’t follow these guidelines,
-  you can report it. See <a href=
-  "http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=113417&topic=2364761&ctx=topic"
-  target="_policies">Inappropriate content in comments and applications</a> for
-  more information.
-</p>
-
-<div class="example-block bad" style="margin-top:3em;width:213px;">
-  <div class="heading">Soliciting ratings</div>
-  <img src="{@docRoot}images/gp-policy-spam-reqrating.png">
-</div>
-
-<h3 id="fake-ratings">Fake or inappropriate ratings and reviews</h3>
-
-<p>
-  To help ensure the quality of ratings and reviews, Google Play policies limit
-  the ways that individuals can use ratings and reviews. In particular, note
-  that it is a violation of policy to use ratings and reviews to influence the
-  placement of any app in Google Play.
-</p>
-
-<p>
-  As an app developer, make sure that you follow these guidelines:
-</p>
-
-<ul>
-  <li>
-    <strong>Don't try to manipulate ratings</strong>&mdash;Do not engage in
-    attempts to manipulate the ratings, reviews, or ranking of your apps,
-    either directly or indirectly, or by manipulating the ratings of your
-    competitors. Do not attempt to artificially boost reviews, ratings, or
-    installs through any means.
-  </li>
-
-  <li>
-    <strong>Don't solicit ratings through incentives</strong>&mdash;Do not
-    offer users any incentives to rate your app, such as offering rewards of
-    any kind or tying app functionality to rating.
-  </li>
-
-  <li>
-    <strong>Don't rate apps multiple times</strong>&mdash;Do not review or
-    rate any app multiple times in an attempt to influence its placement in
-    Google Play.
-  </li>
-
-  <li>
-    <strong>Don't add improper content to reviews</strong>&mdash;Do not
-    include affiliate, coupon, game codes, email addresses, or links to
-    websites or other apps in your reviews. If you are responding to a user
-    review, feel free to include references to helpful resources such as a
-    support address or FAQ page.
-  </li>
-</ul>
-
-<h3 id="solicited-ratings">Soliciting ratings from users</h3>
-
-<p>
-  In general, <strong>do not offer incentives for ratings</strong>. You should
-  not offer users incentives of any kind for rating your app (or any other app)
-  on Google Play, and you should not tie your app's functionality or content to
-  rating in any way.
-</p>
-
-<p>
-  It's acceptable to ask users to rate your app without incentives, for
-  example: "If you like this game, rate us in Google Play!" On the other hand,
-  it's a policy violation to ask users to rate your app based on incentives,
-  for example: "Rate this app and get 500 coins" or "Rate this app 5 stars and
-  get you 500 coins!"
-</p>
-
-
-<h2 id="webview-spam" style="clear:right">Spam in WebViews</h2>
-
-<p>
-  Apps published on Google Play should provide their own content. Do not
-  publish an app whose primary function is to reproduce or frame someone else’s
-  website (unless you have permission).
-</p>
-
-<p>
-  Similarly, do not publish an app whose primary function is to drive affiliate
-  traffic to a website. Although affiliate deals can exist where an app's
-  primary purpose is delivering its own content or functionality, it's a
-  violation of Google Play policies to publish an app whose primary (or
-  only) purpose is to direct affiliate traffic to another website.
-</p>
-
-<div class="example-block bad" style="width:100%;float:none;margin:.5em auto 2em 0;">
-  <div class="heading">WebView spam</div>
-  <table>
-  <tr>
-    <td>App Title:</td>
-    <td>Kids puzzle: Desktop Browser for Turtoogle Game</td>
-  </tr>
-  <tr>
-    <td>Developer:</td>
-    <td>AAZZZ <span style="border:2px solid red;">(not affiliated with Turtoogle
-      Inc.)</span></td>
-  </tr>
-  <tr>
-    <td style="white-space:nowrap;">App Description:</td>
-    <td>
-      <p>Have you ever wanted to use the full, desktop web version of Turtoogle
-        Game from your phone or tablet instead of the Turtoogle Game mobile app
-        or Turtoogle Game mobile web site?</p>
-      <p style="border:2px solid red;">This app lets you access Turtoogle Game
-        on your Android device in the same way as you access the game on your
-        desktop computer, and with all the same Turtoogle Game features.</p>
-    </td>
-  </tr>
-  </table>
-</div>
-
-
-<h2 id="wizard-spam">Spam from Wizards</h2>
-
-<p>
-  Apps that are created by an automated tool or wizard service must not be
-  submitted to Google Play by the operator of that service on behalf of other
-  persons. Such tools often produce too many duplicative or low-quality
-  apps which crowd the higher-quality apps in the Play Store.
-</p>
-
-<p>
-  Please be advised that apps created by an automated tool are only permissible
-  if the app end-product complies with Google Play policies and is published in
-  the Play Store through a developer account that is registered and owned by
-  you.
-</p>
-
-
-<h2 id="message-spam">Spam in Messaging</h2>
-
-<p>
-  Your app may not send SMS, email, or other messages on behalf of the user
-  without providing the user with the ability to confirm the content and intended
-  recipient.
-</p>
-
-<p>
-  Google Play will aggressively remove applications that are found to send or
-  modify SMS messages without user knowledge or consent.
-</p>
\ No newline at end of file
diff --git a/docs/html/distribute/googleplay/promote/index.jd b/docs/html/distribute/googleplay/promote/index.jd
deleted file mode 100644
index 6882990..0000000
--- a/docs/html/distribute/googleplay/promote/index.jd
+++ /dev/null
@@ -1,43 +0,0 @@
-page.title=Promoting Your Apps
-page.metaDescription=Raise the visibility of your apps in Google Play through deep links  and Google Play badges.
-header.hide=0
-footer.hide=0
-@jd:body
-
-<!--
-<style>
-#landing-graphic-container {
-  position: relative;
-}
-
-#text-overlay {
-  position: absolute;
-  left: 0;
-  top: 472px;
-  width: 280px;
-}
-</style>
-
-<div id="landing-graphic-container">
-  <div id="text-overlay">
-   Raise the visibility of your apps with badges and link users to your products on Google Play.
-    <br><br>
-    <a href="{@docRoot}distribute/googleplay/promote/product-pages.html" class="landing-page-link">Your Product Pages</a>
-  </div>
-
-  <a href="{@docRoot}distribute/googleplay/promote/index.html">
-    <img src="{@docRoot}design/media/index_landing_page.png">
-  </a>
-</div> -->
-
-<p>After you publish your app, you can bring Android users to your app's product details page by
-providing links in your social network posts, ad campaigns, app reviews and articles, your
-web site, and more. </p>
-
-<p>You can use the resources in this section to create deep links for your online placements.
-Google Play badges are an especially great way let Android users know that your app is available
-and link them directly to your download page. With the badge generator, they're also easy to make.</p>
-
-
-<p style="margin-top:1.5em;margin-bottom:1.5em;"><a href="{@docRoot}distribute/googleplay/promote/linking.html" class="landing-page-link">Linking to Your Products</a></p>
-
diff --git a/docs/html/distribute/googleplay/promote/product-pages.jd b/docs/html/distribute/googleplay/promote/product-pages.jd
deleted file mode 100644
index af5b2d5..0000000
--- a/docs/html/distribute/googleplay/promote/product-pages.jd
+++ /dev/null
@@ -1,4 +0,0 @@
-page.title=Your Product Pages
-@jd:body
-
-<p>Placeholder...</p>
\ No newline at end of file
diff --git a/docs/html/distribute/googleplay/publish/console.jd b/docs/html/distribute/googleplay/publish/console.jd
deleted file mode 100644
index 3831e51..0000000
--- a/docs/html/distribute/googleplay/publish/console.jd
+++ /dev/null
@@ -1,198 +0,0 @@
-page.title=Developer Console
-@jd:body
-
-
-<p>Once you've <a
-href="{@docRoot}distribute/googleplay/publish/register.html">registered</a> and
-received verification by email, you can sign in to your Google Play
-Developer Console, which will be the home for your app publishing operations and
-tools on Google Play. This sections below introduce a few of the key areas
-you'll find in the Developer Console.</p>
-
-<div class="figure" style="width:756px;">
-<img src="{@docRoot}images/gp-dc-home.png" class="frame">
-<p class="img-caption"><strong>All applications page</strong>: Gives you a quick
-overview of your apps, lets you jump to stats, reviews, and product details, or
-upload a new app. </p>
-</div>
-
-<div class="figure-right" style="width:450px;">
-<img src="{@docRoot}images/gp-dc-profile.png" class="frame">
-<p class="img-caption"><strong>Account details page</strong>: Specifies your developer
-identity and contact information, accounts for app testing, and more.</p>
-</div>
-
-<h3 id="profile">Your account details</h3>
-
-<p>The account details page is where you specify basic information about yourself
-or your company in a developer profile. The information in your developer profile
-is important because it identifies you to Google Play and also to your customers.</p>
-
-<p>During registration you must provide the information for your profile, but you can
-go back at any time to edit the information and change your settings. </p>
-
-<p>Your developer profile contains:</p>
-<ul>
-<li>Your developer name &mdash; the name you want to show users on your store
-listing page and elsewhere on Google Play. </li>
-<li>Your developer contact information &mdash; how Google can contact you if
-needed (this information isn't exposed to users).</li>
-<li>Your developer website URL &mdash; shown to users on your store listing page
-so they can learn more about your company or products.</li>
-</ul>
-
-<p>On the account details page you can also register for a merchant account, set
-up test accounts for Google Play licensing, and more. </p>
-
-<h3 id="user-accounts">Multiple user accounts</h3>
-
-<p>If you are working with a team, you can set up multiple user accounts to
-access different parts of your Developer Console. The first account registered
-is the <em>account owner</em>, with full access to all parts of the Console. The
-owner can add <em>user accounts</em> and manage what parts of the Console they
-have access to. For example, an owner can grant users access to publishing and
-app configuration, but not access to financial reports. </p>
-
-
-<div class="figure-right" style="width:450px;">
-<img src="{@docRoot}images/gp-dc-details.png" class="frame">
-<p class="img-caption"><strong>Store listing page</strong>: Lets you upload your
-graphic assets, description, support information, and other information to
-create the store listing page for a specific app.</p>
-</div>
-
-<h3 id="merchant">Linking your Merchant Account</h3>
-
-<p>If you want to sell apps or in-app products, you can link your Google
-Wallet merchant account to your developer profile. Google Play uses the linked
-merchant account for financial and tax identification and monthly payouts of
-sales. </p>
-
-<h3 id="details">Your store listing details</h3>
-
-<p>The Developer Console lets you set up a colorful storefront page for your app
-called the <em>Store Listing page</em>. Your Store Listing page is the home
-for your app in Google Play &mdash; it's the page users see on their mobile
-phones or on the web when they want to learn about your app and download it.
-</p>
-
-<p>You can upload custom brand assets, screen shots, and videos to highlight
-what's great about your app, and you can provide a localized description, add
-notes about the latest version, and more. You can update your store listing at
-any time, even if you don’t have a new version of your application.</p>
-
-<h3 id="uploading">Uploading and publishing</h3>
-
-<p>From the Developer Console you can quickly upload a release-ready APK and
-publish it when you're ready. The app is a <em>draft</em> until you publish it,
-at which time Google Play makes your store listing page and app available to
-users. You can unpublish the app at any time.</p>
-
-<h3 id="controls">Distribution controls</h3>
-
-<p>In the Developer Console you can manage what countries and territories the
-app is distributed to and, for some countries, you can choose what carriers you
-want to target.</p>
-
-<p>You can also see the list of devices that your app is currently available to,
-based on any distribution rules declared in its manifest file.</p>
-
-<h3 id="selling">Selling and pricing your products</h3>
-
-<p>The Developer Console gives you tools to set prices for your apps and in-app
-products. Your app can either be free to download or priced (charged before
-download). </p>
-
-<div class="sidebox-wrapper">
-<div class="sidebox">
-<p>See <a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=138294&topic=2365624&ctx=topic">Supported locations for distributing applications</a> for a list of countries where you can distribute or sell your app,</p>
-</div>
-</div>
-
-<ul>
-<li>If you publish your app as free, <span style="font-weight:500;">it must
-remain free</span>. Free apps can be downloaded by any users in Google
-Play.</li>
-<li>If you publish it as priced, you can later change it to free. Priced apps can be
-purchased and downloaded only by users who have registered a form of payment
-in Google Play.</li>
-</ul>
-
-<p>In addition, you can sell in-app products and subscriptions in your app,
-whether the app is free or priced. You can set prices separately for priced apps,
-in-app products, and subscriptions.</p>
-
-<p>If you are selling a priced app or in-app products or subscriptions, the
-Developer Console lets you set prices in a large number of different currencies.
-When users around the world visit your store listing, they see the price
-of your app in their own currency. For most countries, the price you set is the
-final price charged to users, inclusive of taxes. </p>
-
-<p>To help you manage your prices, the Developer Console provides an autofill
-capability that uses recent exchange rates to populate the prices in all
-supported currencies. You can change prices for apps and in-app products at any
-time, just by saving changes in the Developer Console.</p>
-
-<h3>In-app Billing</h3>
-
-<div class="sidebox-wrapper">
-<div class="sidebox">
-<h2>In-app Billing</h2>
-<p>For details on how to implement In-app Billing, see the
-<a href="{@docRoot}google/play/billing/index.html">In-app Billing</span></a>
-developer documentation.</p></div></div>
-
-<p><a href="{@docRoot}google/play/billing/index.html">In-app Billing</a> is
-a Google Play service that lets you monetize your apps in more ways by selling
-in-app products and subscriptions. In-app products are one-time purchases, while
-subscriptions are recurring charges on an monthly or annual basis.</p>
-
-<p>From the Developer Console you can create product lists for in-app
-products and subscriptions, set prices, and publish.</p>
-
-<div class="figure-right" style="width:410px;">
-<img src="{@docRoot}images/gp-dc-reviews.png" class="frame">
-<p class="img-caption"><strong>User
-reviews page</strong>: Gives you access to user reviews for a specific app.
-You can filter  reviews in a number of ways to locate issues more easily
-and support your customers more effectively.</p>
-</div>
-
-<h3>User reviews and crash reports</h3>
-
-<p>Google Play makes it easy for users to submit reviews of your app for the
-benefit of other users. The reviews are also extremely important to you, since
-they give you usability feedback, support requests, and important functionality
-issues direct from your customers. </p>
-
-<p>The Developer Console also lets you see crash reports, with stack trace and
-other data, submitted automatically from Android devices, for debugging and
-improving your app.</p>
-
-<h3>App statistics</h3>
-
-<p>The Developer Console gives you detailed statistics on the install
-performance of your app. </p>
-
-<p>You can view installations of your app measured by unique users, as well as
-by unique devices. For user installations, you can view active installs, total
-installs, daily installs and uninstalls, and metrics about user ratings.
-For devices, you can see active
-installs as well as daily installs, uninstalls, and upgrades.</p>
-
-<p>You can zoom into the installation numbers along several dimensions,
-including Android platform version, device, country, language, app version, and
-carrier (mobile operator). You can see the installation data for each dimension
-on a timeline charts.</p>
-
-<p>At a glance, these charts highlight your app’s installation peaks and
-longer-term trends, which you can correlate to promotions, app improvements, or
-other factors. You can even focus in on data inside a dimension by adding
-specific points (such as individual platform versions or languages) to the
-timeline.</p>
-
-<div style="width:530px;">
-<img src="{@docRoot}images/gp-dc-stats.png" class="frame">
-<p class="img-caption"><strong>App statistics page</strong>: Shows you a variety
-of statistics about a specific app's installation performance over time.</p>
-</div>
diff --git a/docs/html/distribute/googleplay/publish/index.jd b/docs/html/distribute/googleplay/publish/index.jd
deleted file mode 100644
index 5a5eaf2..0000000
--- a/docs/html/distribute/googleplay/publish/index.jd
+++ /dev/null
@@ -1,23 +0,0 @@
-page.title=Publishing on Google Play
-header.hide=1
-footer.hide=1
-page.metaDescription=Get started publishing apps on Google Play.
-
-@jd:body
-
-<div style="height:413px;padding-top:50px;">
-    <img src="{@docRoot}images/gp-devconsole-home.png" style="margin-top:0px;">
-</div>
-
-<div style="width:460px;padding-bottom:40px;margin-left:1.5em;"> 
-  <p>Upload apps, build your product pages, configure prices and
-  distribution, and publish. You can manage all phases of publishing
-  on Google Play through the Developer Console, from any web browser.</p>
-
-<p style="margin-top:1.5em;margin-bottom:1.5em;"><a href="{@docRoot}distribute/googleplay/publish/register.html" class="landing-page-link">Get started</a></p>
-</div>
-
-
-
-
-
diff --git a/docs/html/distribute/googleplay/publish/localizing.jd b/docs/html/distribute/googleplay/publish/localizing.jd
deleted file mode 100644
index 1a5f3c1..0000000
--- a/docs/html/distribute/googleplay/publish/localizing.jd
+++ /dev/null
@@ -1,600 +0,0 @@
-page.title=Localization Checklist
-page.tags="localize","localization","resources", "formats", "l10n"
-@jd:body
-
-<div id="qv-wrapper"><div id="qv">
-<h2>Checklist</h2>
-<ol>
-<li><a href="#target-languages">1. Identify target languages</a></li>
-<li><a href="#design">2. Design for localization</a></li>
-<li><a href="#strings">3. Manage strings for localization</a></li>
-<li><a href="#translate">4. Translate UI strings</a></li>
-<li><a href="#test">5. Test your localized app</a></li>
-<li><a href="#prelaunch">6. Prepare for international launch</a></li>
-<li><a href="#support">7. Support international users</a></li>
-</ol>
-<h2>See Also</h2>
-<ol>
-<li><a href="{@docRoot}distribute/googleplay/promote/badges.html">Google Play Badge Builder</a></li>
-<li><a href="{@docRoot}distribute/promote/device-art.html">Device Art Generator</a></li>
-<li><a href="#gp-trans">Translations in Google Play</a></li>
-<li><a href="{@docRoot}sdk/installing/installing-adt.html#tmgr">ADT Translation Manager Plugin</a></li>
-</ol>
-</div></div>
-
-<p>Android and Google Play give you a worldwide audience for your app, with an
-addressable user base that's growing very rapidly in countries such as Japan,
-Korea, India, Brazil, Russia, and elsewhere. </p>
-
-<p>To maximize your app's distribution potential and earn high ratings from
-users around the world, we strongly encourage you to localize your app. </p>
-
-<p>Localization involves a variety of tasks throughout your app's development
-cycle, and advance planning is essential. Some of the tasks include
-translating your UI strings and localizing dates and times, layouts, text
-direction, and finally your Google Play store listing. </p>
-
-<p>This document helps you identify key aspects of localization to prepare for
-and the tasks you'll need to perform, to get your app ready for a
-successful worldwide launch on Google Play.</p>
-
-
-<h2 id="target-languages">1. Identify target languages and locales</h2>
-
-<p>A basic but important step in preparing for localization is identifying the
-countries where you will distribute your app and the languages spoken there.
-Google Play lets you distribute your app broadly to hundreds of countries, reaching
-users who speak a variety of languages. </p>
-
-<p>For international users, you can manage your app on three main dimensions:
-country, locale, and language. Of those, language is the key consideration for
-localization, although locale is also significant because of differences in
-formats for dates, times, currencies, and similar information. Users control
-both the language and locale used on their Android devices and in turn those
-affect the display of your app, once installed.</p>
-
-<p>Typically, you would decide which countries to target first, based on overall
-market size and opportunity, app category, competitive landscape, local pricing
-and financial factors, and so on. Then, based on your country targeting, you
-would determine the languages you need to support in your app. </p>
-
-<p>You will need to decide when to localize into some or all of the languages in your targeted countries. In some countries it might make most sense to deliver an app
-in a major regional or international language only, rather than in all locally
-spoken languages. Similarly, based on overall market size, you might decide to
-deliver your app in only a small number of key languages and offer English or
-another language for other countries. You can add more languages in the future
-as your app's userbase grows.</p>
-
-<p>Localizing your app is particularly important in countries where there is a
-large market opportunity and English or another international language is not
-widely used. Once you have identified your target languages, you can focus your
-development, translation, testing, and marketing efforts to these markets.</p>
-
-
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=138294&topic=2365624&ctx=topic">Supported locations for distributing applications</a></strong> on Google Play.
-.</li>
-</ul>
-</td>
-</tr>
-</table>
-
-
-<h2 id="design">2. Design for localization</h2>
-
-<p>After you've determined your target languages for localization, assess what
-you'll need to do to support them in your app and plan the work early. Consider
-the vocabulary expansion, script requirements, character spacing and wrapping
-constraints, left-to-right and right-to-left support, and other potential
-factors in each language.
-
-<h4>Design a single set of flexible layouts</h4>
-
-<p>As you create your layouts, make sure that any UI elements that hold text are
-designed generously. It’s good to allow more space than necessary for your
-language (up to 30% more is normal) to accommodate other languages.</p>
-
-<p>Also, elements should be able to expand horizontally or vertically to
-accommodate variations in the width and height of UI strings or input text. Your
-text strings should not overlap borders or the screen edge in any of your target
-languages.</p>
-
-<p>If you design your UI carefully, you can typically use a single set of
-layouts for all of the languages you support. See <a
-href="{@docRoot}training/basics/fragments/fragment-ui.html">Building a Flexible
-UI</a> for more information.</p>
-
-<h4 id="rtl">Use alternative layouts where needed</h4>
-
-<p>In cases where your UI can't accommodate text in one of your target
-languages, you can create an <a
-href="{@docRoot}guide/topics/resources/providing-resources.html#AlternativeResources">alternative
-layout</a> for that language only.
-Android makes it easy to declare sets of layouts and other resources to load for
-specific languages, locales, screen sizes, and so on, simply by tagging them
-with the appropriate resource qualifiers. </p>
-
-<p>Although you can use alternative layouts to work around isolated issues, they
-can also make your app harder to maintain over time. In general, using a single,
-more flexible layout is preferred. </p>
-
-<h4 id="rtl">Support RTL layouts and text</h4>
-
-<p>If you are distributing to countries where right-to-left (RTL) scripts are used,
-should consider implementing support for RTL layouts and text display and
-editing, to the extent possible. </p>
-
-<p>Android 4.1 introduced limited support for bidirectional text, allowing apps
-to display and edit text in both left-to-right (LTR) and right-to-left (RTL)
-scripts. Android 4.2 added <a
-href="http://android-developers.blogspot.fr/2013/03/native-rtl-support-in-
-android-42.html">full native support for RTL layouts</a>, including layout
-mirroring, so that you can deliver the same great app experience to all of your
-users. </p>
-
-<p>At a minimum, for Android 4.2 users, it's simple to add basic RTL layout
-mirroring, which goes a long way toward meeting the needs of RTL users. </p>
-
-<h4 id="formats">Use system-provided formats for dates, times, numbers, and
-currencies</h4>
-
-<p>Where your app specifies dates, times, numbers, currencies, and other
-entities that can vary by locale, make sure to use the system-provided formats,
-rather than app-specific formats. Keep in mind that not every locale uses the
-same thousands separator, decimal separator, or percent sign. </p>
-
-<p>Android provides a variety of utilities for formatting and converting
-patterns across locales, such as {@link android.text.format.DateUtils DateUtils} and
-{@link java.text.DateFormat DateFormat} for
-dates; {@link java.lang.String#format String.format()} or {@link java.text.DecimalFormat DecimalFormat} for
-numbers and currency; {@link android.telephony.PhoneNumberUtils
-PhoneNumberUtils} for phone numbers; and others.</p>
-
-<p>If you hard-code your formats based on assumptions about the user's locale,
-your app could encounter problems when the user changes to another locale. The
-easiest and most reliable approach is to always use system-provided formats and
-utilities.</p>
-
-<h4 id="default-resources">Include a full set of default resources</h4>
-
-<p>Make sure that your app can run properly regardless of language or locale by
-providing a complete set of default resources. The app's default resources are
-those that are <em>not marked</em> with any language or locale qualifiers, for
-example those stored in <code>res/drawable/</code> and <code>res/values/</code>.
-If your app attempts to load a resource that isn't available in the current
-language or in the default set, the app will crash. </p>
-
-<p>Whatever the default language you are using in your app, make sure that you
-store the associated layouts, drawables, and strings in default resource
-directories, without language or locale qualifiers.  </p>
-
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a href="http://android-developers.blogspot.fr/2013/03/native-rtl-support-in-android-42.html">Native RTL Support in Android 4.2</a></strong> &mdash; Blog post that explains how to support RTL in your UI.</li>
-<li><strong><a href="{@docRoot}guide/topics/resources/string-resource.html#Plurals">Quantity Strings (Plurals)</a></strong> &mdash; Developer guide describing how to work with string plurals according to rules of grammar in a given locale. </li>
-<li><strong>{@link java.util.Locale Locale}</strong> &mdash; Reference information about how to use locale data determine exactly what CLDR data or version of the Unicode spec a particular Android platform version uses.</li>
-</ul>
-</td>
-</tr>
-</table>
-
-
-<h2 id="managing-strings">3. Manage strings for localization</h2>
-
-<p>It's important to manage your app's UI strings properly, so that you deliver
-a great experience for users and make localization straightforward.</p>
-
-<h4 id="strings">Move all strings into strings.xml</h4>
-
-<p>As you build your app, remember that it's a best practice to keep all of your
-UI strings in a single file that's easy to update and localize. Declare
-<em>all</em> of your strings as resources in a default <code>strings.xml</code>
-file. Do not hard-code any strings into your compiled code&mdash;hard-coded
-strings are much more difficult to extract, translate, and load properly.
-
-<p>If you keep all of your default strings in a <code>strings.xml</code> file,
-you can quickly extract them for translation, and once the translated strings
-are integrated back into your app with appropriate qualifiers, your app can load
-them without any changes to your compiled code.</p>
-
-<p>If you generate images with text, put those strings in <code>strings.xml</code> as well,
-and regenerate the images after translation.</p>
-
-<h4 id="style">Follow Android guidelines for UI strings</h4>
-
-<p>As you design and develop your UI, make sure that you pay close attention to
-<em>how</em> you talk to your user. In general, use a <a
-href="{@docRoot}design/style/writing.html">succinct and compressed style</a>
-that is friendly but brief, and use a consistent style throughout your UI.
-</p>
-
-<p>Make sure that you read and follow the Android Design recommendations for <a
-href="{@docRoot}design/style/writing.html">writing style and word choice</a>.
-Doing so will make your app appear more polished to the user and will help users
-understand your UI more quickly. </p>
-
-<p>Also, always use Android standard terminology wherever possible&mdash;such as
-for UI elements such as "Action Bar," "Options Menu," "System Bar,"
-"Notifications," and so on. Using Android terms correctly and consistently
-makes translation easier and results in a better end-product for users.</p>
-
-<h4 id="context">Provide sufficient context for declared strings</h4>
-
-<p>As you declare strings in your <code>strings.xml</code> file, make sure to describe the
-context in which the string is used. Add comments before each string that may
-need clarification. This information will be invaluable to translators and will
-help you manage your strings more effectively over time.</p>
-
-<p>For example, background information to provide might include:</p>
-
-<ul>
-  <li>What is this string for? When/where is it presented to the user?</li>
-<li>Where is this in the layout? For example, if it’s a button, translations are
-less flexible than if it were a text box. </li>
-</ul>
-
-<p>Here's an example: </p>
-
-<pre>&lt;!-- The action for submitting a form. This text is on a button that can fit 30 chars --&gt;
-&lt;string name="login_submit_button"&gt;Sign in&lt;/string&gt;</pre>
-
-<h4 id="xliff">Mark message parts that should not be translated</h4>
-
-<p>Often strings contain contain text that should not be translated to other
-languages. Common examples might be a piece of code, a placeholder for a value,
-a special symbol, or a name. As you prepare you strings for translation, look
-for and mark text that should remain as-is, without translation, so that
-translators do not change it. </p>
-
-<p>To mark text that should not be translated, use an
-<code>&lt;xliff:g&gt;</code> placeholder tag. Here's an example tag that ensures
-the text “%1$s” will not be changed during translation (otherwise it could break
-the message):</p>
-
-<pre>&lt;string name="countdown"&gt;
-    &lt;xliff:g id="time" example="5 days&gt;%1$s&lt;/xliff:g&gt;until holiday
-&lt;/string&gt;</pre>
-
-<p>When you declare a placeholder tag, always add an <code>id</code> attribute
-that explains what the placeholder is for. If your app will later replace the
-placeholder value, be sure to provide an example attribute to clarify the expected
-usage.</p>
-
-<p>Here are some more examples of placeholder tag usage:</p>
-<pre>&lt;resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"&gt;
-    &lt;!-- Example placeholder for a special unicode symbol --&gt;
-    &lt;string name="star_rating"&gt;Check out our 5 
-        &lt;xliff:g id="star"&gt;\u2605&lt;/xliff:g&gt;
-    &lt;/string&gt;
-    &lt;!-- Example placeholder for a for a URL --&gt;
-    &lt;string name="app_homeurl"&gt;
-        Visit us at &lt;xliff:g id="application_homepage"&gt;http://my/app/home.html&lt;/xliff:g&gt;
-    &lt;/string&gt;
-    &lt;!-- Example placeholder for a name --&gt;
-    &lt;string name="prod_name"&gt;
-        Learn more at &lt;xliff:g id="prod_gamegroup"&gt;Game Group&lt;/xliff:g&gt;
-    &lt;/string&gt;
-    &lt;!-- Example placeholder for a literal --&gt;
-    &lt;string name="promo_message"&gt;
-        Please use the ”&lt;xliff:g id="promotion_code"&gt;ABCDEFG&lt;/xliff:g&gt;” to get a discount.
-    &lt;/string&gt;
-    ...
-&lt;/resources&gt;</pre>
-<!--<pre>&lt;string name="contact_info"&gt;
-    You can see our posts at &lt;xliff:g id="social_account_id"&gt;@superApp&lt;/xliff:g&gt;
-&lt;/string&gt;</pre>-->
-
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<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>
-</td>
-</tr>
-</table>
-
-
-<h2 id="translate">4. Translate UI strings and other resources</h2>
-
-<p>Translating your app's UI strings and resources to your target languages is
-the key phase of localization, and it's the one that requires the most care and
-planning.</p>
-
-<p>In general, it's recommended to work with a professional translator to ensure
-that the work goes smoothly, stays on schedule, and results in a high-quality
-product that will enhance the value of your app. If you are considering machine
-translations as an alternative, keep in mind that automated translations are less
-reliable than high-quality professional translations and may not produce as good an
-experience for your users.</p>
-
-<h4>Prepare for translation</h4>
-
-<p>Getting high-quality translation output depends in part on your input. To get
-ready for translation, make sure that your <code>strings.xml</code> file is well organized,
-well commented, and accurate.</p>
-
-<p>Here are some ways to prepare your strings for translation:</p>
-<ul>
-  <li>Make sure your strings are formatted correctly and consistently.</li>
-  <li>Follow the strings recommendations listed in <a href="#strings">Manage
-strings for localization</a>, above.</li>
-  <li>Clean up the <code>strings.xml</code> file and remove unused strings.</li>
-  <li>Place comments in the file to identify the owner, origin, and the version
-of the file, as well as any special instructions for translators.</li>
-<li>Identify existing translations, if any, and include those in an outgoing
-zip file or other package that you will send to translators.</li>
-<li>Identify drawables or other resources that require translation and include
-them in the outgoing package for translators.</li>
-<p>Additionally, consider translating your app's store listing details &mdash;
-app title and description, release notes, and so on &mdash; as
-well as other international marketing materials.</p>
-<li>Create a terminology list that explains the meaning and usage of key terms
-used in your product, your market, or the underlying technology. Add the list to
-the outgoing package.</li>
-</ul>
-
-<h4 id="send">Send your strings for translation</h4>
-
-<p>Early in the development cycle, contact professional translation vendors for
-your target languages to get an idea of cost, lead time required, turnaround
-time, and so on. Then select a vendor and secure their services, making sure to
-include multiple iterations in the cost as a safeguard. Google Play can help you
-do this &mdash; see <a href="#gp-trans">Purchase professional
-translations</a>, below.</p>
-
-<p>As soon as your app's UI strings and design are stable, work with your
-development team to extract all of the strings and other resources from the app
-and package them together for the translator. If appropriate, you can version
-the outgoing package for later identification. </p>
-
-<p>When the outgoing package is ready, send it to the translator or share it
-with them over a cloud platform such as Google Drive. Keep a record of what you
-sent and when you sent it, to cross-reference against returning translations and
-billing invoices from the translator.</p>
-
-<p>When your translations are complete, take a preliminary look at the
-translations. Check that all files were translated, check for potential encoding
-issues, and make sure that declaration formats are intact. </p>
-
-<p>If everything looks good, carefully move the localized directories and files 
-back into your app's resources. Make sure to tag the directories with the
-appropriate language and locale qualifiers so that they'll later be loaded
-properly.</p>
-
-<p>After the translations are merged back into your app, start <a
-href="#testing">testing the localized app</a>.</p>
-
-<h4 id="gp-trans">Purchase professional translations through Google Play
-<br />App Translation Service</h4>
-
-<div class="sidebox-wrapper">
-<div class="sidebox">
-<h2>App Translations in Google Play</h2>
-
-<p>Hear from developers who have used the Google Play App Translation Service in <a
-href="{@docRoot}distribute/googleplay/spotlight/localization.html">Developer
-Stories: Localization in Google Play</a>.</p>
-
-<p>To make it easy to export your app's strings and import
-the finished translations into your project, try the <a
-href="{@docRoot}sdk/installing/installing-adt.html#tmgr">
-ADT Translation Manager Plugin</a>.</div>
-</div>
-
-<p>Google Play App Translation Service can help you quickly find and purchase translations of your app.
-In the Developer Console, you can browse a list of third-party vendors who are
-pre-qualified by Google to offer high-quality translation at competitive prices.
-You can upload the strings you want translated, select the languages you want to
-translate into, and select your translation vendor based on time and price.</p>
-
-<p>Once you've purchased translations, you'll receive an email from your vendor.
-Your translations are a direct business agreement between you and your vendor;
-you'll need to work directly with the vendor to manage the translation process and
-deliverables and resolve any support issues. </p>
-
-
-<h2 id="testing">5. Test your localized app</h2>
-
-<p>Once you've received your translated strings and resources and moved them
-back into your app, you need to test the app to make sure that it's ready for
-distribution to your international users. </p>
-
-<p>Manual testing can help you discover localization issues in your layouts and
-strings that can affect user satisfaction and, ultimately, your app's user
-rating. </p>
-
-<h4 id="native">Set up a test environment</h4>
-
-<p>To test your localized app, you'll need to set up an environment consisting
-of multiple devices (or virtual devices) and screen sizes, based on the markets
-and form factors you are targeting. Note that the range of devices in specific
-regions might be different. If possible, match your test devices to the actual
-devices likely to be available to users.</p>
-
-<h4 id="native">Look for common localization issues</h4>
-
-<p>On each test device, set the language or locale in Settings. Install and
-launch the app and then navigate through all of the UI flows, dialogs, and user
-interactions. Enter text in inputs. Some things to look for include:</p>
-
-<ul>
-  <li>Clipped text, or text that overlaps the edge of UI elements or the
-screen</li>
-  <li>Poor line wrapping</li>
-  <li>Incorrect word breaks or punctuation</li>
-  <li>Incorrect alphabetical sorting</li>
-  <li>Incorrect layout direction or text direction</li>
-  <li>Untranslated text &mdash; if your default strings are displayed instead of
-translated strings, then you may have overlooked those strings for translation
-or marked the resources directory with an incorrect language qualifier. </li>
-</ul>
-
-<p>For cases where your strings have expanded in translation and no longer fit
-your layouts, it's recommended to simplify your default text, simplify your
-translated text, or adjust your default layouts. If none of those resolves the
-issue, you can create a custom layout for the language. </p>
-
-<h4 id="default-test">Test for default resources</h4>
-
-<p>After you've tested your app in all of your supported languages and locales,
-make sure to test it again in an <em>unsupported language</em> and locale. This
-will help you make sure that your app includes a full set of default strings and
-resources, so that your app is usable to all users, regardless of their
-preferred language. </p>
-
-<h4 id="native">Review with native-language speakers</h4>
-
-<p>During or after testing, it's recommended that you let native speakers review
-your localized app. One way to do that is through beta testing with regional
-users &mdash; Google Play can help you do this. See <a href="#beta">Plan a beta
-release</a> for more information.</p>
-
-
-<h2 id="prelaunch">Prepare for international launch</h2>
-
-<p>Getting your app translated is a key part of localization, but to help your
-product attract users and gain visibility, you should prepare for launch in your
-target countries and create a broader launch and marketing plan for
-international users. </p>
-
-
-<h4 id="listing">Localize your Google Play listing</h4>
-
-<div class="sidebox-wrapper">
-<div class="sidebox">
-<h2>Localize your Google Play listing</h2>
-<p>Highlight what's great about your app to all of your users! Localize your
-listing in the Developer Console: </p>
-<ul>
-  <li>App title and description</li>
-  <li>App screenshots on phones and tablets</li>
-  <li>Promotional graphics and videos.</li>
-</ul>
-</div>
-</div>
-<p>If you want your app to be successful in international markets, it's
-essential to localize your Google Play store listing. You can manage your
-localized listing in the Developer Console.</p> 
-
-<p>Well before launch, decide on your app title, description, promotional text,
-marketing names and programs, and other text and images. Send your
-listing text and images for translation early, so that you have them ready when
-beta testing begins. When your translated text is available, you can add it
-through the Developer Console.</p>
-
-<p>Also, since you've made the effort to create a great localized app, let users
-know about it! Take screenshots of your UI in each language, for phones and 7-
-and 10- inch tablets. You can upload screenshots to the Developer Console for
-each language you support. These will be of great value to users browsing your
-app listing in other languages. </p>
-
-<p>It's also essential to create localized versions of your promotional graphics
-and videos. For example, your app's feature graphic might include text that
-should be translated, for maximum effectiveness, or you might want to take a
-different visual approach in one country than you do in another. You can create
-different versions of your promotional graphics for each language and upload
-them to the Developer Console. If you offer a promotional video, you can create
-localized versions of it and then add a link to the correct localized video for
-each language you support.</p>
-<h4 id="beta">Plan a beta release in key countries</h4>
-
-<div class="sidebox-wrapper">
-<div class="sidebox">
-<h2>Easy beta testing</h2>
-<p>Google Play now lets you set up groups of alpha and beta testers, anywhere
-around the world. Check out this powerful feature next time you sign in to the
-Developer Console.</p>
-</div>
-</div>
-
-<p>Before launching your app, it's always valuable to get real-world feedback
-from users &mdash; even more so when you are launching an app in a new language,
-country, or region. In those cases, it's highly recommended that you distribute
-a pre-release version of your app to users across your key markets and provide
-an easy means for them to provide feedback and report bugs. </p>
-
-<p>Google Play can help you set up a beta program for your app. After you sign
-in to the Developer Console and upload your APK, you can set up groups of users
-for alpha testing and beta testing the app. You can start with a small group of
-alpha testers, then move to a larger group of beta testers. Once users are
-added, they access your app's store listing and install the app. User feedback
-from alpha and beta testers goes directly to you and is not posted as public
-reviews. </p>
-
-<p>The feedback you receive will help you adjust your UI, translations, and
-store listing to ensure a great experience for users. </p>
-
-<h4 id="beta">Plan for international marketing</h4>
-
-<p>For highest visibility across countries, consider an international marketing
-or advertising campaign. The scope of the campaign might vary based on the
-budget you can support, but in general it's cost-effective and productive to do
-regional or country-specific marketing at launch and after. </p>
-
-<h4 id="badges">Create localized Google Play badges</h4>
-
-<p>If you are preparing international marketing, make sure to include a <a
-href="{@docRoot}distribute/googleplay/promote/badges.html">localized Google Play
-badge</a> to tell users you're on Google Play. You can use the badge generator
-to quickly build localized badges that you can use on web sites or marketing
-materials. High-resolution assets are also available.</p> 
-
-<h4 id="deviceart">Create Localized Device Art</h4>
-
-<p>If you feature product shots of your app running on Android devices, make
-sure that those shots look great and reflect the latest in Android devices. To
-help you create high-quality marketing materials, use the drag-and-drop <a
-href="{@docRoot}distribute/promote/device-art.html">Device Art Generator</a> to
-quickly frame your screen shot on a Nexus device. </p>
-
-<h4 id="deviceart">Check your Optimization Tips</h4>
-
-<p>As you prepare for launch, make sure to sign into the Developer Console and check
-your app's Optimization Tips. The Optimization Tips let you know when you are missing parts of your localized store listing and provide other helpful reminders for a successful localized launch.</p>
-
-<h2 id="support">Support International Users after Launch</h2>
-
-<p>After you launch your app internationally, you should be prepared to support
-users in a variety of languages and time zones. The extent of your international
-user support depends on your budget, but at a minimum you should watch your
-ratings, reviews, and download stats carefully after launch. 
-
-<p>Here are some suggestions: </p>
-
-<ul>
-  <li>Use the app stats in the Developer Console to compare your downloads,
-installs, and uninstalls, and ratings across languages and countries&mdash;If
-your downloads or ratings are not keeping up in specific languages or countries,
-consider options for improving your product or changing your marketing approach.
-</li>
-  <li>Check reviews regularly&mdash;Google Play translates all user reviews for
-you, so you can stay in touch with how international users feel about your app,
-what features they like and what issues are affecting them. By watching reviews,
-you can spot technical issues that may affect many users in a particular
-country, then fix and update your app.</li>
-  <li>Respond to reviews if possible&mdash;It's good to engage with
-international users in their language or a common language if possible. If not,
-you can try using translation tools, although results may not be predictable. If
-your app gets very popular in a language, consider getting support help from
-native-language speakers. </li>
-  <li>Make sure there's a link to any support resources on your web site.
-Consider setting up language-specific user groups, Google+ communities, or other
-support forums.
-</ul>
-
-<p>By following these practices for localizing your app, promoting and marketing
-to international users, and providing ongoing support, you can attract many new
-users to your app and maintain their loyalty.</p>
-
-<p>Make sure to read the <a
-href="{@docRoot}distribute/googleplay/publish/preparing.html">Launch
-Checklist</a> to learn more about how to plan, build, and launch your app on
-Google Play. </p>
diff --git a/docs/html/distribute/googleplay/publish/preparing.jd b/docs/html/distribute/googleplay/publish/preparing.jd
deleted file mode 100644
index b9dd0e0..0000000
--- a/docs/html/distribute/googleplay/publish/preparing.jd
+++ /dev/null
@@ -1,681 +0,0 @@
-page.title=Launch Checklist
-page.tags="publishing","launch","Google Play", "Developer Console"
-@jd:body
-
-<div id="qv-wrapper"><div id="qv">
-<h2>Checklist</h2>
-<ol>
-<li><a href="#process">1. Understand the publishing process</a></li>
-<li><a href="#policies">2. Understand Google Play policies</a></li>
-<li><a href="#core-app-quality">3. Test for core app quality</a></li>
-<li><a href="#rating">4. Determine your content rating</a></li>
-<li><a href="#countries">5. Determine country distribution</a></li>
-<li><a href="#size">6. Confirm the app's overall size</a></li>
-<li><a href="#compatibility">7. Confirm app compatibility ranges</a></li>
-<li><a href="#free-priced">8. Decide on free or priced</a></li>
-<li><a href="#inapp-billing">9. Consider In-app Billing</a></li>
-<li><a href="#pricing">10. Set prices for your apps</a></li>
-<li><a href="#localize">11. Start localization early</a></li>
-<li><a href="#graphics">12. Prepare promotional graphics</a></li>
-<li><a href="#apk">13. Build the release-ready APK</a></li>
-<li><a href="#beta">14. Plan a beta release</a></li>
-<li><a href="#product-page">15. Complete the product details</a></li>
-<li><a href="#badges">16. Use Google Play badges</a></li>
-<li><a href="#final-checks">17. Final checks and publishing</a></li>
-<li><a href="#support">18. Support users after launch</a></li>
-</ol>
-</div></div>
-
-
-<p>Before you publish your app on Google Play and distribute it to users, you
-need to get the app ready, test it, and prepare your promotional materials. </p>
-
-<p>This document helps you understand the publishing process and get ready for a
-successful product launch on Google Play. It summarizes some of the
-tasks you'll need to complete before publishing your app on Google Play, such as
-creating a signed, release-ready APK, understanding the requirements of the app,
-and creating the product page and graphic assets for your app.</p>
-
-<p>The preparation and publishing tasks are numbered to give you a rough idea of
-sequence. However, you can handle the tasks in any sequence that works for you
-or you can skip steps as appropriate.</p>
-
-<p>As you move toward publishing, a variety of support resources are available to
-you. Relevant links are provided in each step.</p>
-
-
-<h2 id="process">1. Understand the publishing process</h2>
-
-<p>Before you begin the steps in this checklist, you should take a moment to
-read and understand the overall publishing workflow and become familiar with how
-the process works. In particular, you or your development team will need to
-prepare your app for release using a process common to all Android apps.
-The <a
-href="{@docRoot}tools/publishing/publishing_overview.html">Publishing
-Workflow</a> documents provide the details on how publishing works and how to
-get an APK ready for release. </p>
-
-<p>Once you are familiar with publishing in general, read this document to
-understand the issues that you should consider when publishing an app on Google
-Play. </p>
-
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a href="{@docRoot}tools/publishing/publishing_overview.html">General Publishing Overview</a></strong> &mdash; Start here for an overview of publishing options for Android apps.</li>
-<li><strong><a href="{@docRoot}tools/publishing/preparing.html">Preparing for Release</a></strong> &mdash; Developer documentation on how to build the signed, release-ready APK. This process is the same for all Android apps. </li>
-</ul>
-</td>
-</tr>
-</table>
-
-<h2 id="policies">2. Understand Google Play policies and agreements</h2>
-
-<p>Make sure that you understand and follow the Google Play program policies
-that you accepted when registering. Google Play actively enforces the policies
-and any violations can lead to suspension of your app or, for repeated
-violations, termination of your developer account. </p>
-
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-
-<li><strong><a href="{@docRoot}distribute/googleplay/policies/index.html">Google Play Policies and Guidelines</a></strong> &mdash; An overview of Google Play policies for spam, intellectual property, and ads, with examples of common problems. </li>
-</a></strong> &mdash; Help Center document describing various content policies and processes.</li>
-
-<li><strong><a href="http://support.google.com/googleplay/android-developer/bin/topic.py?hl=en&topic=2364761&parent=2365624&ctx=topic">Policy and Best Practices
-</a></strong> &mdash; Help Center document describing various content policies and processes.</li>
-
-</ul>
-</td>
-</tr>
-</table>
-
-<h2 id="core-app-quality">3. Test for Core App Quality</h2>
-
-<p>Before you publish an app on Google Play, it's important to make sure that
-it meets the basic quality expectations for all Android apps, on all of the devices that you
-are targeting. You can check your app's quality by setting up a test
-environment and testing the app against a short set of <strong>core app quality criteria</strong>.
-For complete information, see the <a
-href="{@docRoot}distribute/googleplay/quality/core.html">Core App Quality Guidelines</a>. 
-</p>
-
-<p>If your app is targeting tablet devices, make sure that it delivers a rich, compelling
-experience to your tablet customers. See the <a
-href="{@docRoot}distribute/googleplay/quality/tablet.html">Tablet App Quality Checklist</a>
-for recommendations on ways to optimize your app for tablets.</p>
-
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a
-href="{@docRoot}distribute/googleplay/quality/core.html">Core App Quality
-Guidelines</a></strong> &mdash; A set of core quality criteria that all Android
-apps should meet on all targeted devices.</li>
-<li><strong><a
-href="{@docRoot}distribute/googleplay/quality/tablet.html">Tablet App Quality
-Checklist</a></strong> &mdash; A set recommendations for delivering the best
-possible experience to tablet users.</li>
-</ul>
-</td>
-</tr>
-</table>
-
-<h2 id="rating">4. Determine your app's content rating</h2>
-
-<p>Google Play requires you to set a content rating for your app, which informs
-Google Play users of its maturity level. Before you publish, you should confirm
-what rating level you want to use. The available content rating levels are:</p>
-
-<ul>
-<li>Everyone</li>
-<li>Low maturity</li>
-<li>Medium maturity</li>
-<li>High maturity</li>
-</ul>
-
-<p>On their Android devices, Android users can set the desired maturity level
-for browsing. Google Play then filters apps based on the setting, so the content
-rating you select can affect the app's distribution to users. You can assign (or
-change) the content rating for your app in the Developer Console, so no changes
-are required in your app binary.</p>
-
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=188189">Rating your application content for Google Play</a></strong> &mdash; Help Center document describing content ratings levels and how to choose the appropriate one for your app.</li>
-</ul>
-</td>
-</tr>
-</table>
-
-<h2 id="countries">5. Determine country distribution</h2>
-
-<p>Google Play lets you control what countries and territories your app is
-distributed to. For widest reach and the largest potential customer base, you
-would normally want to distribute to all available countries and territories.
-However, because of business needs, app requirements, or launch dependencies,
-you might want to exclude one or more countries from your distribution. </p>
-
-<p>It's important to determine the exact country distribution early, because it
-can affect:</p>
-<ul>
-<li>The need for localized resources in the app</li>
-<li>The need for a localized app description in the Developer Console</li>
-<li>Legal requirements for the app that may be specific to certain
-countries</li>
-<li>Time zone support, local pricing, and so on.</li>
-</ul>
-
-<p>With your country targeting in mind, you should assess what
-your localization needs are, both in your app and in its Google Play listing
-details, and start the work of localization well in advance of your
-launch target date.</p>
-
-<p>See <a href="{@docRoot}distribute/googleplay/publish/localizing.html">Localization
-Checklist</a> for key steps and considerations in the localizing process. </p>
-
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a href="{@docRoot}distribute/googleplay/publish/localizing.html">Localization Checklist</a></strong> &mdash; Overview of key steps and considerations for localizing your Android app.</li>
-<li><strong><a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=138294&topic=2365624&ctx=topic">Supported locations for distributing applications</a></strong> on Google Play.
-.</li>
-</ul>
-</td>
-</tr>
-</table>
-
-<h2 id="size">6. Confirm the app's overall size</h2>
-
-<p>The overall size of your app can affect its design and how you publish it on
-Google Play. Currently, the maximum size for an APK published on Google Play is
-<strong>50 MB</strong>. If your app exceeds that size, or if you want to offer a
-secondary download, you can use <a
-href="{@docRoot}google/play/expansion-files.html">APK Expansion Files</a>,
-which Google Play will host for free on its server infrastructure and
-automatically handle the download to devices.</p>
-
-<ul>
-<li>The maximum size for an APK published on Google Play is 50 MB.</li>
-<li>You can use up to two (2) APK Expansion Files, each up to 2 GB in size, for
-each APK.</li>
-</ul>
-
-<p>Using APK Expansion files is a convenient, cost-effective method of
-distributing large apps. However, the use of APK Expansion Files requires some
-changes in your app binary, so you will need to make those changes before
-creating your release-ready APK.</p>
-
-<p>To minimize the size of your app binary, make sure that you run the
-<a href="{@docRoot}tools/help/proguard.html">Proguard</a> tool on your code when
-building your release-ready APK.</p>
-
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a href="{@docRoot}google/play/expansion-files.html">APK Expansion Files</a></strong>
-&mdash; Developer documentation describing APK Expansion Files and how to support them in your app.</li>
-<li><strong><a href="{@docRoot}tools/help/proguard.html">ProGuard</a></strong> &mdash; Developer
-documentation describing how to use ProGuard to shrink, optimize, and obfuscate your code prior
-to release.</li>
-</ul>
-</td>
-</tr>
-</table>
-
-<h2 id="compatibility">7. Confirm the app's platform and screen compatibility ranges</h2>
-
-<p>Before publishing, it's important to make sure that your app is designed to
-run properly on the Android platform versions and device screen sizes that you
-want to target. 
-
-<p>From an app-compatibility perspective, Android platform versions are defined
-by <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#ApiLevels">API level</a>. You should
-confirm the minimum version that your app is compatible with (<a
-href="{@docRoot}guide/topics/manifest/uses-sdk-element.html"><code>&lt;minSdkVersion&gt;</code></a>),
-as that will affect its distribution to Android
-devices once it is published. </p>
-
-<p>For screen sizes, you should confirm that the app runs properly and looks
-good on the range of screen sizes and densities that you want to support. You
-should confirm the minimum screen-size and density support that your app
-declares (<a
-href="{@docRoot}guide/topics/manifest/supports-screens-element.html"><code>&lt;supports-screens&gt;</code></a>),
-since that can affect its distribution to
-Android devices once it is published. </p>
-
-<p>To get a better understanding of the current device penetration of Android
-platform versions and screen sizes across all Android devices, see the <a
-href="{@docRoot}about/dashboards/index.html">Device Dashboard</a>
-charts.</p>
-
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a href="{@docRoot}about/dashboards/index.html">Device Dashboard</a></strong> &mdash; A chart showing global percentages of devices by Android version, screen size, and level of OpenGL ES support.</li>
-<li><strong><a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#ApiLevels">Android API Levels</a></strong> &mdash; A definition of API Levels and a list of which Android platform versions they are associated with. </li>
-</ul>
-</td>
-</tr>
-</table>
-
-<h2 id="free-priced">8. Decide whether your app will be free or priced</h2>
-
-<p>On Google Play, you can publish apps as free to download or priced. Free apps
-can be downloaded by any Android user in Google Play.
-Paid apps can be downloaded only by users who have registered a form of payment
-in Google Play, such as a credit card or Direct Carrier Billing.</p>
-
-<p>Deciding whether you app will be free or paid is important because, on Google
-Play, <strong>free apps must remain free</strong>.</p>
-
-<ul>
-<li>Once you publish your app as a free app, you cannot ever change it to being
-a priced app. However, you can still sell in-app products and
-subscriptions through Google Play's In-app Billing service.</li>
-<li>If you publish your app as a priced app, you <em>can</em> change
-it at any time to being a free app (but cannot then change it back to
-priced). You can also sell in-app products and subscriptions. </li>
-</ul>
-
-<p> If your app is be priced, or if you'll be selling in-app products,
-you need set up a Google Wallet merchant account before you can publish.</p>
-
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a href="{@docRoot}google/play/billing/index.html">In-app Billing</a></strong> &mdash; Developer introduction to Google Play In-app Billing.</li>
-</ul>
-</td>
-</tr>
-</table>
-
-<h2 id="inapp-billing">9. Consider using In-app Billing</h2>
-
-<p>Google Play <a href="{@docRoot}google/play/billing/index.html">In-app
-Billing</a> lets you sell digital content in your applications. You can use the
-service to sell a wide range of content, including downloadable content such as
-media files or photos, and virtual content such as game levels or potions.
-In-app Billing service lets you sell one-time purchases and subscriptions from
-inside your app. This can help you to monetize the app over its installed
-lifetime. </p>
-
-<p>If your are looking for more ways to monetize your app and build engagement,
-you should consider In-app Billing. The service has become very popular with
-both users and developers. To use In-app Billing, you need to make changes to
-your app binary, so you will need to complete and test your implementation
-before creating your release-ready APK.</p>
-
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a href="{@docRoot}google/play/billing/index.html">In-app Billing</a></strong> &mdash; Developer documentation describing In-app Billing and how to support it in your app.</li>
-</ul>
-</td>
-</tr>
-</table>
-
-<h2 id="pricing">10. Set prices for your products</h2>
-
-<p>If your app is priced or you will sell in-app products, Google Play lets you
-set prices for your products in a variety of currencies, for users in markets
-around the world. You can set prices individually in different currencies, so
-you have the flexibility to adjust your price according to market conditions and
-exchange rates. </p>
-
-<p>Before you publish, consider how you will price your products
-and what your prices will be in various currencies. Later, you can set prices
-in all available currencies through the Developer Console.</p>
-
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=1169947&topic=15867&ctx=topic">Selling Apps in Multiple Currencies
-</a></strong> &mdash; Help Center document describing how pricing works in Google Play.</li>
-
-<li><strong><a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=138412&topic=15867&ctx=topic">Prices and supported currencies
-</a></strong> &mdash; Help Center document listing supported currencies for pricing your apps.</li>
-
-<li><strong><a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=112622&topic=15867&ctx=topic">Transaction Fees
-</a></strong> &mdash; Help Center document describing transaction fees for priced apps and in-app products.</li>
-
-<li><strong><a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=138000&topic=15867&ctx=topic">Specifying tax rates
-</a></strong> &mdash; Help Center document describing how to set tax rates for different countries. </li>
-
-</ul>
-</td>
-</tr>
-</table>
-
-<h2 id="localize">11. Start localization</h2>
-
-<p>With your country targeting in mind, it's a good idea to assess your localization
-needs and start the work of localizing well in advance of your target
-launch date.</p>
-
-<p>There are at least three aspects of localization to consider:</p>
-
-<ul>
-<li>Localizing the strings, images, and other resources in your app</li>
-<li>Localizing your app's store listing details on Google Play</li>
-<li>Localizing the app's graphic assets, screenshots, and videos that accompany your store listing.</li>
-</ul>
-
-<p>See <a href="{@docRoot}distribute/googleplay/publish/localizing.html">Localization Checklist</a> for key steps and considerations in the localizing process. </p>
-
-<p>To localize your store listing, first create and finalize your app title, description, 
-and promotional text. Collect and send all of these for localization. You can optionally
-translate the "Recent Changes" text for app updates as well. Later you can add your localized
-listing details in the Developer Console, or you can  choose to let Google Play auto-translate
-your listing details into the languages you support.</p>
-
-<p>A key part of making your app listing attractive to a global customer base is
-creating localized versions of your promotional graphics, screenshots and
-videos. For example, your app's feature graphic might include text that should
-be translated, for maximum effectiveness. You can create different versions of
-your promotional graphics for each language and upload them to the Developer
-Console. If you offer a promotional video, you can create localized versions of
-it and then add a link to the correct localized video for each language you
-support.</p>
-
-<p>When your translations are complete, move them into your app resources as needed and test
-that they are loaded properly. Save your app's translated listing details for later,
-when you upload assets and configure your product details.</p>
-
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a href="{@docRoot}distribute/googleplay/publish/localizing.html">Localization Checklist</a></strong> &mdash; Overview of key steps and considerations for localizing your Android app.</li>
-<li><strong><a href="{@docRoot}guide/topics/resources/localization.html">Localizing with Resources</a></strong> &mdash; Developer guide to localizing resources in your app.</li>
-</ul>
-</td>
-</tr>
-</table>
-
-<h2 id="graphics">12. Prepare promotional graphics, screenshots, and videos</h2>
-
-<p>When you publish on Google Play, you can supply a variety of high-quality
-graphic assets to showcase your app or brand. After you publish, these appear on
-your product details page, in store listings and search results, and elsewhere.
-These graphic assets are key parts of a successful product details page that
-attracts and engages users, so you should consider having a professional produce
-them for you. Screen shots and videos are also very important, because they show
-what your app looks like, how it's used or played, and what makes it different.</p>
-
-<p>All of your graphic assets should be designed so that they are easy to see
-and highlight your app or brand in a colorful, interesting way. The assets
-should reference the same logo and icon as users will actually find in the All
-Apps launcher once they have downloaded the app. Your graphic assets should also
-fit in well with the graphic assets of other apps published by you, which will
-be also be displayed to users on your product details page. </p>
-
-<p>To help you market your app more effectively to a global audience, Google
-Play lets you create localized versions of your promotional graphics,
-screenshots, and videos and upload them to the Developer Console. When a user
-visits your app's store listing, Google Play displays the promotional graphic,
-screenshots and video that you've provided for the user's language.</p>
-
-<p>To localize your promotional graphics, you can translate any embedded text, use
-different imagery or presentation, or change your marketing approach to best address the needs
-of users in specific languages. For example, if your feature or promotional graphic
-includes and embedded product name or tag line, you can translate that text
-and add it to a localized version of the promotional graphic.</p>
-
-<p>Because your localized graphic assets and videos are so important, you should get
-started on creating them and localizing them well in advance of your target
-publishing date. </p>
-
-<p class="note"><strong>Note:</strong> Localized promotional graphics and videos
-are supported only in the new Developer Console design.</p>
-
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=1078870">Graphic Assets for your Application
-</a></strong> &mdash; Details about the graphic assets you need to upload before publishing.</li>
-<li><strong><a href="http://android-developers.blogspot.com/2011/10/android-market-featured-image.html">Google Play Featured Image Guidelines
-</a></strong> &mdash; Blog post that highlights key design considerations for your app's featured image.</li>
-</ul>
-</td>
-</tr>
-</table>
-
-<h2 id="apk">13. Build and upload the release-ready APK</h2>
-
-<p>When you are satisfied that your app meets your UI, compatibility, and
-quality requirements, you can build the release-ready version of the app. The
-release-ready APK is what you you will upload to the Developer Console and
-distribute to users. 
-
-<p>The process for preparing a release-ready APK is the same for all apps,
-regardless of how they are distributed. Generally the process includes basic code cleanup
-and optimization, building and signing with your release key, and final testing.
-When you are finished preparing your application for release, you'll have a signed
-APK file that you can upload to the Developer Console for distribution to
-users. </p>
-
-<p>For complete details on how to create a release-ready version of your app,
-read <a href="{@docRoot}tools/publishing/preparing.html">Preparing for
-Release</a>.</p>
-
-<p>Once you have the release-ready APK in hand, you can upload it to 
-the Developer Console. If necessary, you can replace the APK with a more 
-recent version before publishing. </p>
-
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a href="{@docRoot}tools/publishing/preparing.html">Preparing for Release</a></strong> &mdash; Essential information for preparing and packaging your app properly for distribution.</li>
-</ul>
-</td>
-</tr>
-</table>
-
-<h2 id="beta">14. Plan a beta release</h2>
-
-<div class="sidebox-wrapper">
-<div class="sidebox">
-<h2>Easy beta testing</h2>
-<p>Google Play now lets you set up groups of alpha and beta testers, anywhere around the world. Check out this powerful feature next time you sign in to the Developer Console.</p>
-</div>
-</div>
-
-<p>Before launching your app, it's always valuable to get real-world feedback
-from users &mdash; even more so when you are launching a new app. It's highly
-recommended that you distribute a pre-release version of your app to users
-across your key markets and provide an easy means for them to provide feedback
-and report bugs. </p>
-
-<p>Google Play can help you set up a beta program for your app. After you sign
-in to the Developer Console and upload your APK, you can set up groups of users
-for alpha testing and beta testing the app. You can start with a small group of
-alpha testers, then move to a larger group of beta testers. Once users are
-added, they access your app's store listing and install the app. User feedback
-from alpha and beta testers goes directly to you and is not posted as public
-reviews. </p>
-
-<p>The feedback you receive will help you adjust your UI, translations, and
-store listing to ensure a great experience for users. </p>
-
-<h2 id="product-page">15. Complete the app's product details</h2>
-
-<p>On Google Play, your app's product information is shown to users on its
-product details page, the page that users visit to learn more about your app and
-the page from which they will decide to purchase or download your app, on their
-Android devices or on the web.</p>
-
-<p>Google Play gives you a variety of ways to promote your app and engage with
-users on your product details page, from colorful graphics, screenshots, and
-videos to localized descriptions, release details, and links to your other apps.
-As you prepare to publish your app, make sure that you take advantage of all
-that your product details page can offer, making your app as compelling as
-possible to users.</p>
-
-<p>You should begin planning your product page in advance of your target launch
-date, arranging for localized description, high-quality graphic assets,
-screenshots and video, and so on. </p>
-
-<p>As you get near your target publishing date, you should become familiar with 
-all the fields, options, and assets associated with the product details configuration
-page in the Developer Console. As you collect the information and assets for the
-page, make sure that you can enter or upload it to the Developer Console, until 
-the page is complete and ready for publishing. </p>
-
-<p>After you've set your app's geographic targeting in the Developer Console,
-remember to add your localized product details, promotional graphics, and so on, for all of the
-languages that you support.</p>
-
-<p>If your app is targeting tablet devices, make sure to include at least one screen
-shot of the app running on a tablet, and highlight your app's support for tablets
-in the app description, release notes, promotional campaigns, and elsewhere.</p>
-
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=113475&topic=2365760&ctx=topic">Category types
-</a></strong> &mdash; Help Center document listing available categories for apps.</li>
-<li><strong><a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=1078870&topic=2365760&ctx=topic">Graphic Assets for your Application
-</a></strong> &mdash; Help Center document describing the various graphics you can add to your product listing.</li>
-</ul>
-</td>
-</tr>
-</table>
-
-<h2 id="badges">16. Use Google Play badges and links in your promotional
-campaigns</h2>
-
-<p>Google Play badges give you an officially branded way of promoting your app
-to Android users. Use the <a
-href="{@docRoot}distribute/googleplay/promote/badges.html">Google Play Badge
-generator</a> to quickly create badges to link users to your products from web
-pages, ads, reviews, and more. You can also use special <a
-href="{@docRoot}distribute/googleplay/promote/linking.html">link formats</a>
-to link directly to your product details page, to a list of your products, or to
-search results.</p>
-
-<p>To help your app get traction after launch, it's strongly recommended that you support 
-launch with a promotional campaign that announces your product through many channels as
-possible, in as many countries as possible. For example, you can promote the launch 
-using ad placements, social network or blog posts, video and other media, interviews
-and reviews, or any other channel available.</p>
-
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a href="{@docRoot}distribute/googleplay/promote/badges.html">Google Play Badges</a></strong> &mdash; Generate a badge to bring users to your app in Google Play.</li>
-<li><strong><a href="{@docRoot}distribute/googleplay/promote/linking.html">Linking to Your Products</a></strong> &mdash; Link formats that you can use to bring users to your app in Google Play.</li>
-</ul>
-</td>
-</tr>
-</table>
-
-<h2 id="final-checks">17. Final checks and publishing</h2> 
-
-<p>When you think you are ready to publish, sign in to the Developer Console and take a few moments for a few
-final checks.</p>
-
-<p>Make sure that: </p>
-
-<ul>
-<li>Your developer profile has the correct information and is linked to the proper Google Wallet merchant account (if you are selling products).</li>
-<li>You have the right version of the app uploaded.</li>
-<li>All parts of your Product Details are ready, including all graphic assets, screenshots, video, localized descriptions, and so on. </li>
-<li>You have set your app's pricing to free or priced.</li>
-<li>You have set country (and carrier) targeting and priced your products (if appropriate) in buyer currencies</li>
-<li>"Compatible devices" shows that your app is actually reaching the devices that you are targeting. If not, you should check with your development team on the apps requirements and filtering rules. </li>
-<li>You have provided the correct link to your web site and the correct support email address.</li>
-<li>Your app does not violate content policy guidelines.</li>
-<li>You have acknowledged that your app meets the guidelines for Android content on Google Play and also US export laws. </li>
-</ul>
-
-<p>Your app is now ready to publish!</p>
-
-<p>If you are releasing an update, make sure to read the <a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=113476&topic=2365760&ctx=topic">requirements for publishing updates</a>. </p>
-
-<p>When you are ready, click the <strong>Publish</strong> button in the Developer Console. Within a few hours, your app will become available to users and your product page will be appear in Google Play for browsing, searching, or linking from your promotional campaigns.</p>
-
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a href="http://www.android.com/us/developer-content-policy.html">Google Play Developer Program Policies</a></strong> &mdash; Guidelines for what is acceptable conent in Google Play. Please read and understand the policies before publishing. </li>
-<li><strong><a href="{@docRoot}distribute/googleplay/promote/linking.html">Updates</a></strong> &mdash; Requirements for app updates in Google Play.</li>
-<li><strong><a href="{@docRoot}support.html">Developer Support</a></strong> &mdash; Support resources that you can use to find answers and report issues.</li>
-</ul>
-</td>
-</tr>
-</table>
-
-
-<h2 id="support">18. Support users after launch</h2>
-
-<p>After you publish an app or an app update, it's crucial for you to support
-your customers. Prompt and courteous support can provide a better experience for
-users that results in better ratings and more positive reviews for your
-products. Users are likely to be more engaged with your app and recommend it if
-you are responsive to their needs and feedback.  This is especially true after
-publishing if you are using a coordinated promotional campaign.</p>
-
-<p>There are a number of ways that you can keep in touch with users and offer
-them support. The most fundamental is to provide your <em>support email
-address</em> on your product details page. Beyond that, you can provide support
-in any way you choose, such as a forum, mailing list or a Google+ page.  The
-Google Play team does provide user support for downloading, installing and
-payments issues, but issues that fall outside of these topics will fall under
-your domain.  Examples of issues you can support include:  feature requests,
-questions about using the app and questions about compatibility settings.  </p>
-
-<p>After publishing, plan to: </p>
-<ul>
-<li>Check your ratings and reviews frequently on your app's product details
-page. Watch for recurring issues that could signal bugs or other issues. </li>
-<li>Be mindful of new Android platform version launches, as compatibility
-settings for your apps might need to be updated.</li>
-<li>Put a link to your support resources on your web site and set up any other
-support such as forums.</li>
-<li>Provide an appropriate support email address on your product details page
-and respond to users when they take the time to email you.</li>
-<li>Beyond the automatic refund window offered by Google Play, be generous with
-your own refund policy, as satisfied users will be more likely to purchase in
-the future. </li>
-<li>Acknowledge and fix issues in your app. It helps to be transparent and
-list known issues on your product details page proactively.  </li>
-<li>Publish updates as frequently as you are able, without sacrificing quality
-or annoying users with too-frequent updates. </li>
-<li>With each update, make sure to provide a summary of what's changed. You can
-enter this information in the Developer Console. Users will read it and
-appreciate that you are serious about improving the quality of your app. </li>
-</ul>
-
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<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/payments/answer/2741495?rd=1">Issuing Refunds</a></strong> &mdash;  -- Help Center document describing how to issue refunds.</li>
-</ul>
-</td>
-</tr>
-</table>
-
-
-
diff --git a/docs/html/distribute/googleplay/publish/register.jd b/docs/html/distribute/googleplay/publish/register.jd
deleted file mode 100644
index faade81..0000000
--- a/docs/html/distribute/googleplay/publish/register.jd
+++ /dev/null
@@ -1,80 +0,0 @@
-page.title=Get Started with Publishing
-@jd:body
-
-<div id="qv-wrapper">
-<div id="qv">
-<h2>Help topics</h2>
-<ul>
-  <li><a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=113468">Developer Registration</a></li>
-  <li><a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=138294&topic=2365624&ctx=topic">Supported Locations for Distributing Apps</a></li>
-  <li><a href="http://support.google.com/googleplay/android-developer/bin/topic.py?hl=en&topic=2364761">Policy and Best Practices</a></li>
-  <li><a href="http://support.google.com/googleplay/android-developer/">Developer Support</a></li>
-</ul>
-
-<h2>Get Started</h2>
-<ol>
-  <li><a href="https://play.google.com/apps/publish/">Google Play Developer Console</a></li>
-</ol>
-
-</div>
-</div>
-
-<p>You can set up to start publishing on Google Play in only a few minutes. Here's how you do it: </p>
-
-<ul>
-<li>Register for a Google Play publisher account</li>
-<li>If you will sell apps, set up a Google Wallet Merchant Account</li>
-<li>Explore the Google Play Developer Console and learn about the tools for publishing</li>
-</ul>
-
-
-<h3>Register for a publisher account</h3>
-
-<p>The first step is to visit the Google Play Developer Console and register for a publisher account.</p>
-
-<p>Here's what you will do during registration: </p>
-
-<div class="sidebox-wrapper">
-<div class="sidebox">
-<h2>Tips</h2>
-  <ul>
-    <li>You need a Google account to register. You can create one during the process. </li>
-    <li>If you are an organization, consider registering a new Google account rather than using a personal account.</li>
-    <li>Review the <a href="https://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=138294">developer countries</a> and <a href="https://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=150324">merchant countries</a> where you can distribute and sell apps.</li> 
-  </ul>
-</div></div>
-
-
-<ol>
-<li>Visit the Google Play Developer Console at <a
-href="https://play.google.com/apps/publish/">https://play.google.com/apps/publish/</a>.
-<li>Enter basic information about your <strong>developer identity</strong> &mdash; developer
-name, email address, and so on. You can modify this information later.</li>
-<li>Read and accept the <strong>Developer Distribution Agreement</strong> that applies to your
-country or region. Note that apps and store listings that you publish on Google Play must comply
-with the Developer Program Policies and US export law,</li>
-<li>Pay a <strong>$25 USD registration fee</strong> using Google Wallet. If you don't have
-a Google Wallet account, you can quickly set one up during the process.</li>
-</ol>
-
-<p>When your registration is verified, you’ll be notified at the email address you specified during registration.</p>
-
-<h3>Set up a Google Wallet Merchant account</h3>
- 
-<p>If you want to sell products on Google Play &mdash; priced apps, in-app products, or subscriptions &mdash; you will also need to set up a Google Wallet Merchant Account. You can do that at any time, but make sure to first review the list of <a href="https://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=150324">merchant countries</a>.</p>
-
-<p>To set up a Merchant account from the Developer Console:</p>
-
-<ol>
-<li><strong>Sign in</strong> to your Google Play Developer Console at
-<a href="https://play.google.com/apps/publish/">https://play.google.com/apps/publish/</a>
-<li>Open <strong>Financial reports</strong> <img src="{@docRoot}images/distribute/console-reports.png"
-  style="vertical-align:baseline;margin:0"> on the side navigation.
-<li>Click <strong>Setup a Merchant Account now</strong>.</li>
-</ol>
-
-<p>This takes you to the Google Wallet site to sign up as a Merchant;
-you'll need information about your business available to complete this step.</p>
-
-<h3>Explore the Developer Console</h3>
-<p>When your registration is verified, you can sign in to your Developer Console, which will be the home for your app publishing operations and tools on Google Play. </p>
diff --git a/docs/html/distribute/googleplay/quality/core.jd b/docs/html/distribute/googleplay/quality/core.jd
deleted file mode 100644
index 9e23bcc..0000000
--- a/docs/html/distribute/googleplay/quality/core.jd
+++ /dev/null
@@ -1,804 +0,0 @@
-page.title=Core App Quality Guidelines
-@jd:body
-
-<div id="qv-wrapper"><div id="qv">
-<h2>Quality Criteria</h2>
-  <ol>
-    <li><a href="#ux">Design and Interaction</a></li>
-        <li><a href="#fn">Functionality</a></li>
-        <li><a href="#ps">Performance and Stability</a></li>
-        <li><a href="#listing">Google Play</a></li>
-
-  </ol>
-  
-  <h2>Testing</h2>
-  <ol>
-    <li><a href="#test-environment">Setting Up a Test Environment</a></li>
-        <li><a href="#tests">Test Procedures</a></li>
-        </ol>
-
-  <h2>You Should Also Read</h2>
-  <ol>
-    <li><a href="{@docRoot}distribute/googleplay/quality/tablet.html">Tablet App Quality Checklist</a></li>
-        <li><a href="{@docRoot}distribute/googleplay/strategies/app-quality.html">Improving App Quality</a></li>
-  </ol>
-  
-
-</div>
-</div>
-
-<p>App quality directly influences the long-term success of your app&mdash;in
-terms of installs, user rating and reviews, engagement, and user retention.
-Android users expect high-quality apps, even more so if they've spent money on
-them.</p>
-
-<p>This document helps you assess basic aspects of quality in your app through a
-compact set of <em>core app quality criteria</em> and associated tests. All
-Android apps should meet these criteria.</p>
-
-<p>Before publishing your app, make sure to test it against these criteria to
-ensure that it functions well on many devices, meets Android standards for
-navigation and design, and is prepared for promotional opportunities in the
-Google Play Store. Your testing will go well beyond what's described here&mdash;the
-purpose of this document is to specify the essential characteristics
-of basic quality so that you can include them in your test plans.</p>
-
-<p>If your app is targeting tablet devices, make sure that it delivers a rich,
-compelling experience to your tablet customers. See the <a
-href="{@docRoot}distribute/googleplay/quality/tablet.html">Tablet App Quality
-Checklist</a> for recommendations on ways to optimize your app for tablets.</p>
-
-
-<h2 id="ux">Visual Design and User Interaction</h2>
-
-<p>These criteria ensure that your app provides standard Android visual design
-and interaction patterns where appropriate, for a consistent and intuitive
-user experience.</p>
-
-<table>
-	<tr>
-		<th style="width:2px;">
-			Area
-		</th>
-		<th style="width:54px;">
-			ID
-		</th>
-		
-
-		<th>
-			Description
-		</th>
-		<th style="width:54px;">
-			Tests
-		</th>
-	</tr>
-	<tr id="UX-B1">
-	<td>Standard design</td>
-		<td>
-		UX-B1	
-		</td>
-		<td>
-			<p style="margin-bottom:.5em;">App follows <a href="{@docRoot}design/index.html">Android Design</a> guidelines and uses common <a href="{@docRoot}design/patterns/index.html">UI patterns and icons</a>:</p>
-			<ol style="margin-bottom:.5em;list-style-type:lower-alpha">
-			<li>App does not redefine the expected function of a system icon (such as the Back button).</li>
-			<li>App does not replace a system icon with a completely different icon if it triggers the standard UI behavior. </li>
-			<li>If the app provides a customized version of a standard system icon, the icon strongly resembles the system icon and triggers the standard system behavior.</li>
-			<li>App does not redefine or misuse Android UI patterns, such that icons or behaviors could be misleading or confusing to users.</li>
-			</ol>
-		</td>
-		<td><a href="#core">CR-all</a></td>
-	</tr>
-
-
-	<tr>
-		<td rowspan="3">Navigation</td>
-		<td id="UX-N1">
-			UX-N1
-		</td>
-
-		<td>
-			<p>App supports standard system <a href="{@docRoot}design/patterns/navigation.html">Back button navigation</a> and does not make use of any custom, on-screen "Back button" prompts.</p>
-		</td>
-		<td><a href="#core">CR-3</a></td>
-	</tr>
-	<tr>
-		<td id="UX-N2">
-			UX-N2 
-		</td>
-		<td>
-			<p>All dialogs are dismissable using the Back button.</p>
-		</td>
-		<td><a href="#core">CR-3</a></td>
-	</tr>
-
-	<tr  id="UX-N3">
-		<td>
-			UX-N3
-		</td>
-		<td>
-			Pressing the Home button at any point navigates to the Home screen of the device. 
-		</td>
-		<td><a href="#core">CR-1</a></td>
-	</tr>
-	<tr  id="UX-S1">
-			<td rowspan="2">Notifications</td>
-		<td>
-			UX-S1
-		</td>
-		<td>
-			<p style="margin-bottom:.5em;">Notifications follow Android Design <a href="{@docRoot}design/patterns/notifications.html">guidelines</a>. In particular:</p>
-			<ol style="margin-bottom:.5em;list-style-type:lower-alpha">
-			<li>Multiple notifications are stacked into a single notification object, where possible.</li>
-			<li>Notifications are persistent only if related to ongoing events (such as music playback or a phone call).</li>
-			<li>Notifications do not contain advertising or content unrelated to the core function of the app, unless the user has opted in.</li>
-			</ol>
-
-		</td>
-		<td><a href="#core">CR-11</a></td>
-	</tr>
-	<tr id="UX-S2">
-
-		<td>
-			UX-S2
-		</td>
-
-		<td>
-		
-			<p style="margin-bottom:.5em;">App uses notifications only to:</p>
-			<ol style="margin-bottom:.5em;list-style-type:lower-alpha">
-			<li>Indicate a change in context relating to the user personally (such as an incoming message), or</li>
-			<li>Expose information/controls relating to an ongoing event (such as music playback or a phone call).</li>
-			</ol>
-		</td>
-		<td><a href="#core">CR-11</a></td>
-	</tr>
-
-	</table>
-
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a href="{@docRoot}design/index.html">Android Design</a></strong> &mdash; Overview of design and user experience best practices for Android apps. </li>
-<li><strong><a href="{@docRoot}design/patterns/navigation.html">Navigation with Back and Up</a></strong> &mdash; Android Design document describing standard navigation patterns. </li>
-<li><strong><a href="{@docRoot}design/patterns/actionbar.html">Action Bar</a></strong> &mdash; Android Design document describing how to use the Action Bar. </li>
-<li><strong><a href="{@docRoot}design/style/iconography.html">Iconography</a></strong> &mdash;  Android Design describing how to use various types of icons.</li>
-<li><strong><a href="{@docRoot}design/patterns/notifications.html">Notifications</a></strong> &mdash;  Android Design document describing how to design and use notifications. </li>
-</ul>
-</td>
-</tr>
-</table>
-
-<h2 id="fn">Functionality</h2>
-
-<p>These criteria ensure that your app provides expected functional behavior with the appropriate level of permissions. </p>
-
-<table>
-	<tr>
-		<th style="width:2px;">
-			Area
-		</th>
-		<th style="width:54px;">
-			ID
-		</th>
-		
-
-		<th>
-			Description
-		</th>
-		<th style="width:54px;">
-			Tests
-		</th>
-	</tr>
-
-	<tr id="FN-P1">
-	<td rowspan="2">Permissions</td>
-		<td>
-		FN-P1
-		</td>                                                                                                                                                                      
-		<td>App requests only the <em>absolute minimum</em> permissions that it needs to support core functionality.
-		</td>
-		<td rowspan="2"><a href="#core">CR-11</a></td>
-	</tr>
-	<tr id="FN-P2">
-		<td>
-			FN-P2
-		</td>                                                                                                                                                                      
-		<td><p style="margin-bottom:.5em;">App does not request permissions to access sensitive data (such as Contacts or the System Log) or services that can cost the user money (such as the Dialer or SMS), unless related to a core capability of the app.
-		</td>
-	</tr>
-	<tr id="FN-L1">
-		<td>Install location</td>
-		<td>
-			FN-L1
-		</td>
-		<td>
-			<p style="margin-bottom:.5em;">App functions normally when installed on SD card (if supported by app).</p>
-			
-			<p style="margin-bottom:.25em;">Supporting installation to SD card is recommended for most large apps (10MB+). See the <a href="{@docRoot}guide/topics/data/install-location.html">App Install Location</a> developer guide for information about which types of apps should support installation to SD card.</p>
-			</td>
-			
-			<td><a href="#SD-1">SD-1</a>
-			</td>
-	</tr>
-	<tr id="FN-A1">
-	<td rowspan="4">Audio</td>
-		<td>
-			FN-A1
-		</td>
-
-		<td>
-			Audio does not play when the screen is off, unless this is a core feature (for example, the app is a music player).
-		</td>
-		<td><a href="#core">CR-7</a></td>
-	</tr>
-	<tr id="FN-A2">
-		<td>
-			FN-A2
-		</td>
-		<td>
-			Audio does not <a href="http://android-developers.blogspot.com/2011/11/making-android-games-that-play-nice.html">play behind the lock screen</a>, unless this is a core feature.
-		</td>
-		<td><a href="#core">CR-8</a></td>
-	</tr>
-	<tr id="FN-A3">
-		<td>
-			FN-A3
-		</td>
-		<td>
-			Audio does not play on the home screen or over another app, unless this is a core feature.
-		</td>
-		<td><a href="#core">CR-1, <br />CR-2</a></td>
-	</tr>
-	<tr id="FN-A4">
-		<td>
-			FN-A4
-		</td>
-		<td>
-			Audio resumes when the app returns to the foreground, or indicates to the user that playback is in a paused state.
-		</td>
-		<td><a href="#core">CR-1, CR-8</a></td>
-	</tr>
-	<tr id="FN-U1">
-	<td rowspan="3">UI and Graphics</td>
-		<td>
-			FN-U1
-		</td>
-		<td>
-			<p style="margin-bottom:.5em;">App supports both landscape and portrait orientations (if possible).</em></p>
-			<p style="margin-bottom:.25em;">Orientations expose largely the same features and actions and preserve functional parity.
-			Minor changes in content or views are acceptable.</p>
-		</td>
-		<td><a href="#core">CR-5</a></td>
-	</tr>
-	<tr id="FN-U2">
-		<td>
-			FN-U2
-		</td>
-		<td>
-		<p style="margin-bottom:.5em;">App uses the whole screen in both orientations and does not letterbox to account for orientation changes.</em></p>
-		<p style="margin-bottom:.25em;">Minor letterboxing to compensate for small variations in screen geometry is acceptable.</p>
-		</td>
-		<td><a href="#core">CR-5</a></td>
-	</tr>
-	<tr id="FN-U3">
-		<td>
-			FN-U3
-		</td>
-		<td>
-			<p style="margin-bottom:.5em;">App correctly handles rapid transitions between display orientations without rendering problems.</p>
-		</td>
-		<td><a href="#core">CR-5</a></td>
-	</tr>
-	
-	<tr  id="FN-S1">
-		<td rowspan="2">User/app state</td>
-		<td>
-			FN-S1
-		</td>
-		<td>
-		<p style="margin-bottom:.5em;">App should not leave any services running when the app is in the background, unless related to a core capability of the app.</p>
-		<p style="margin-bottom:.25em;">For example, the app should not leave services running to maintain a network connection for notifications, to maintain a Bluetooth connection, or to keep the GPS powered-on.</p>
-		</td>
-		<td><a href="#core">CR-6</a></td>
-	</tr>
-	<tr  id="FN-S2">
-		<td>
-			FN-S2
-		</td>
-		<td>
-			<p style="margin-bottom:.5em;">App correctly preserves and restores user or app state.</p>
-			<p style="margin-bottom:.25em;">App preserves user or app state when leaving the foreground and prevents accidental data loss due to back-navigation and other state changes. When returning to the foreground, the app must restore the preserved state and any significant stateful transaction that was pending, such as changes to editable fields, game progress, menus, videos, and other sections of the app or game.</p>
-			<ol style="margin-bottom:.25em;list-style-type:lower-alpha">
-			<li>When the app is resumed from the Recents app switcher, the app returns the user to the exact state in which it was last used.</li>
-			<li>When the app is resumed after the device wakes from sleep (locked) state, the app returns the user to the exact state in which it was last used.</li>
-			<li>When the app is relaunched from Home or All Apps, the app restores the app state as closely as possible to the previous state.</li>
-			<li>On Back keypresses, the app gives the user the option of saving any app or user state that would otherwise be lost on back-navigation.</li>
-			</ol>
-		</td>
-		<td><a href="#core">CR-1, CR-3, CR-5</a></td>
-	</tr>
-	
-</table>
-
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a href="http://android-developers.blogspot.com/2011/11/making-android-games-that-play-nice.html">Making Android Apps that Play Nice</a></strong> &mdash; Developer blog post discussing the audio lifecycle and expected audio behaviors for Android apps. </li>
-<li><strong><a href="{@docRoot}guide/components/tasks-and-back-stack.html">Tasks and Back Stack</a></strong> &mdash; Developer guide describing how to implement back-navigation.</li>
-<li><strong><a href="{@docRoot}training/basics/activity-lifecycle/recreating.html">Recreating an Activity</a></strong> &mdash; Android Training class the shows how to preserve and restore app state.</li>
-
-</ul>
-</td>
-</tr>
-</table>
-
-
-<h2 id="ps">Performance and Stability</h2>
-
-<p>To ensure a high user rating, your app needs to perform well and stay
-responsive on all of the devices and form factors and screens that it is
-targeting. These criteria ensure that the app provides the basic performance,
-stability, and responsiveness expected by users.</p>
-
-<table>
-	<tr>
-		<th style="width:2px;">
-			Area
-		</th>
-		<th style="width:54px;">
-			ID
-		</th>
-		<th>
-			Description
-		</th>
-		<th style="width:54px;">
-			Tests
-		</th>
-	</tr>
-	<tr  id="PS-S1">
-		<td>Stability</td>
-		<td>
-			PS-S1
-		</td>
-		<td>
-			App does not crash, force close, freeze, or otherwise function abnormally on any targeted device.
-		</td>
-		<td><a href="#core">CR-all</a>, <a href="#SD-1">SD-1</a>, <a href="#HA-1">HA-1</a></td>
-	</tr>
-	
-	<tr id="PS-P1">
-	<td rowspan="2">Performance</td>
-		<td>
-			PS-P1
-		</td>
-		<td>
-			App loads quickly or provides onscreen feedback to the user (a progress indicator or similar cue) if the app
-			takes longer than two seconds to load.
-		</td>
-		<td>
-		    <a href="#core">CR-all</a>, <a href="#SD-1">SD-1</a>
-		</td>
-	</tr>
-	<tr id="PS-P2">
-
-		<td>
-			PS-P2
-		</td>
-		<td>
-			With StrictMode enabled (see <a href="#strictmode">StrictMode Testing</a>, below), no red flashes (performance warnings from StrictMode) are visible when exercising the app, including
-			during game play, animations and UI transitions, and any other part of the app.
-		</td>
-		<td>
-		    <a href="#PM-1">PM-1</a>
-		</td>
-	</tr>
-	<tr id="PS-M1">
-		<td>Media</td>
-		<td>
-			PS-M1
-		</td>
-		<td>
-			Music and video playback is smooth, without crackle, stutter, or other artifacts, during normal app usage and load.
-		</td>
-		<td>
-		    <a href="#core">CR-all</a>, <a href="#SD-1">SD-1</a>, <a href="#HA-1">HA-1</a>
-		</td>
-	</tr>
-	<tr id="PS-V1">
-		<td rowspan="2">Visual quality</td>
-	<td>
-			PS-V1
-		</td>
-		<td>
-			<p style="margin-bottom:.5em;">App displays graphics, text, images, and other UI elements without noticeable distortion, blurring, or pixelation.</p>
-			
-			<ol style="margin-bottom:.5em;list-style-type:lower-alpha">
-			<li>App provides high-quality graphics for all targeted screen sizes and form factors, including for <a href="{@docRoot}distribute/googleplay/quality/tablet.html">larger-screen devices such as tablets</a>.</li>
-			<li>No aliasing at the edges of menus, buttons, and other UI elements is visible.</li>
-			</ol>
-		</td>
-		<td rowspan="2"><a href="#core">CR-all</a></td>
-	</tr>
-	<tr id="PS-V2">
-		<td>
-			PS-V2
-		</td>
-		<td>
-			<p style="margin-bottom:.5em;">App displays text and text blocks in an acceptable manner. </p>
-			
-		 <ol style="margin-bottom:.5em;list-style-type:lower-alpha">
-			<li>Composition is acceptable in all supported form factors, including for larger-screen devices such as tablets.</li>
-			<li>No cut-off letters or words are visible.</li>
-			<li>No improper word wraps within buttons or icons are visible.</li>
-			<li>Sufficient spacing between text and surrounding elements.</li>
-			</ol>
-		</td>
-
-	</tr>
-</table>
-
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a href="http://android-developers.blogspot.com/2010/12/new-gingerbread-api-strictmode.html">Using StrictMode</a></strong> &mdash; Developer blog post discussing StrictMode and how to use it for performance monitoring in your app. </li>
-<li><strong><a href="{@docRoot}guide/practices/responsiveness.html">Designing for Responsiveness</a></strong> &mdash; Developer guide describing best practices for keeping your app responsive.</li>
-<li><strong><a href="http://android-developers.blogspot.com/2010/07/multithreading-for-performance.html">Multithreading for Performance</a></strong> &mdash; Developer blog post discussing ways to improve performance through multi-threading.</li>
-</ul>
-</td>
-</tr>
-</table>
-
-
-<h2 id="listing">Google Play</h2>
-
-<p>To launch your app successfully on Google Play, raise its ratings, and make
-sure that it is ready for promotional activities in the store, follow the
-criteria below.</p>
-
-<table>
-	<tr>
-		<th style="width:2px;">
-			Area
-		</th>
-		<th style="width:54px;">
-			ID
-		</th>
-		<th>
-			Description
-		</th>
-		<th style="width:54px;">
-			Tests
-		</th>
-	</tr>
-	<tr id="GP-P1">
-	<td rowspan="2">Policies</td>
-		<td>
-			GP-P1
-		</td>
-		<td>
-			App strictly adheres to the terms of the <a href="http://play.google.com/about/developer-content-policy.html">Google Play Developer Content Policy</a> and does not offer inappropriate content, does not use intellectual property or brand of others, and so on.
-		</td>
-		<td>
-		<a href="#gp">GP-all</a>
-		</td>
-	</tr>
-	
-	<tr id="GP-P2">
-		<td>
-			GP-P2
-		</td>
-		<td>
-			<p style="margin-bottom:.5em;">App maturity level is set appropriately, based on the 
-			<a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=188189">Content Rating Guidelines</a>.</p>
-			
-			<p style="margin-bottom:.25em;">Especially, note that apps that request permission to use the device location cannot be given the maturity level "Everyone". </p>
-		</td>
-			<td>
-		<a href="#gp">GP-1</a>
-		</td>
-	</tr>
-
-	<tr id="GP-D1">
-	<td rowspan="3">App&nbsp;Details Page</td>
-		<td>
-			GP-D1
-		</td>
-		<td>
-			<p style="margin-bottom:.5em;">App feature graphic follows the guidelines outlined in this
-			<a href="http://android-developers.blogspot.com/2011/10/android-market-featured-image.html">blog post</a>. Make sure that:</p>
-			
-			<ol style="margin-bottom:.5em;list-style-type:lower-alpha">
-				<li>The app listing includes a high-quality feature graphic.</li>
-				<li>The feature graphic does not contain device images, screenshots, or small text that will be illegible when scaled down and displayed on the smallest screen size that your app is targeting.</li>
-			    <li>The feature graphic does not resemble an advertisement.</li>
-			</ol>
-			
-		
-		</td>
-		
-				<td>
-		<a href="#gp">GP-1, GP-2</a>
-		</td>
-	</tr>
-	<tr id="GP-D2">
-		<td>
-			GP-D2
-		</td>
-		<td>
-			App screenshots and videos do not show or reference non-Android devices. 
-		</td>
-		<td rowspan="2"><a href="#gp">GP-1</a></td>
-	</tr>
-	<tr id="GP-D3">
-		<td>
-			GP-D3
-		</td>
-		<td>
-			App screenshots or videos do not 
-			represent the content and experience of your app in a misleading way.
-		</td>
-	</tr>
-	<tr id="GP-X1">
-		<td>User Support</td>
-		<td>
-			GP-X1
-		</td>
-		<td>Common user-reported bugs in the Reviews tab of the Google Play page are addressed if they are
-			reproducible and occur on many different devices. If a bug occurs on only a few devices,
-			you should still address it if those devices are particularly popular or new.
-		</td>
-		
-				<td>
-		<a href="#gp">GP-1</a>
-		</td>
-		
-	</tr>
-</table>
-
-<table>
-<tr>
-<td><p>Related resources:</p>
-<ul style="margin-top:-.5em;">
-<li><strong><a href="https://play.google.com/apps/publish/">Launch Checklist</a></strong> &mdash; Recommendations on how to prepare your app for publishing, test it, and launch successfully on Google Play.</li>
-<li><strong><a href="http://play.google.com/about/developer-content-policy.html">Google Play Developer Program Policies</a></strong> — Guidelines for what is acceptable conent in Google Play. Please read and understand the and understand the policies before publishing.</p>
-<li><strong><a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&amp;answer=188189">Rating your application content for Google Play</a></strong> — Help Center document describing content ratings levels and how to choose the appropriate one for your app.</li>
-<li><strong><a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&amp;answer=1078870">Graphic Assets for your Application
-</a></strong> — Details about the graphic assets you need to upload before publishing.</li>
-<li><strong><a href="http://android-developers.blogspot.com/2011/10/android-market-featured-image.html">Google Play Featured Image Guidelines
-</a></strong> — Blog post discussing how to create an attractive, effective Featured Image for your app.</li>
-<li><strong><a href="http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&amp;answer=113477&amp;topic=2364761&amp;ctx=topic">Supporting your users
-</a></strong> — Help Center document describing options for supporting users.</li>
-</ul>
-</td></tr>
-</table>
-
-
-<h2 id="test-environment">Setting Up a Test Environment</h2>
-
-<p>To assess the quality of your app, you need to set up a suitable
-hardware or emulator environment for testing. </p>
-
-<p>The ideal test environment would
-include a small number of actual hardware devices that represent key form
-factors and hardware/software combinations currently available to consumers.
-It's not necessary to test on <em>every</em> device that's on the market &mdash;
-rather, you should focus on a small number of representative devices, even using
-one or two devices per form factor. </p>
-
-<p>If you are not able to obtain actual hardware devices for testing, you should
-<a href="{@docRoot}tools/devices/index.html">set up emulated devices (AVDs)</a>
-to represent the most common form factors and
-hardware/software combinations.</p>
-
-<p>To go beyond basic testing, you can add more devices, more form factors, or
-new hardware/software combinations to your test environment. You can also
-increase the number or complexity of tests and quality criteria. </p>
-
-
-<h2 id="tests">
-  Test Procedures
-</h2>
-
-<p>These test procedures help you discover various types of quality issues in
-your app. You can combine the tests or integrate groups of tests together in
-your own test plans. See the sections above for references that associate
-specific criteria with specific tests. </p>
-
-<table>
-	<tr>
-		<th style="width:2px;">
-			Type
-		</th>
-		<th style="width:54px;">
-			Test
-		</th>
-		<th>
-			Description
-		</th>
-	</tr>
-	<tr>
-		<td rowspan="12" id="core">Core Suite</td>
-		<td>
-			CR-0
-		</td>
-		<td><p style="margin-bottom:.5em;">Navigate to all parts of the app &mdash; all screens, dialogs, settings, and all user flows. </p>
-		
-		<ol style="margin-bottom:.5em;list-style-type:lower-alpha">
-		<li>If the application allows for editing or content creation, game play, or media playback, make sure to enter those flows to create or modify content.</li>
-		<li>While exercising the app, introduce transient changes in network connectivity, battery function, GPS or location availability, system load, and so on. </li>
-			</ol>
-		</td>
-	</tr>
-	<tr id="tg2">
-		<td id="core">
-			CR-1
-		</td>
-		<td>From each app screen, press the device's Home key, then re-launch the app from the All Apps screen.
-		</td>
-	</tr>
-	<tr id="CR-2">
-		<td>
-			CR-2
-		</td>
-		<td>From each app screen, switch to another running app and then return to the app under test using the Recents app switcher.
-		</td>
-	</tr>
-
-	<tr id="CR-3">
-		<td>
-			CR-3
-		</td>
-		<td>From each app screen (and dialogs), press the Back button. 
-		</td>
-	</tr>
-		<tr id="CR-5">
-		<td>
-			CR-5
-		</td>
-		<td>From each app screen, rotate the device between landscape and portrait orientation at least three times.
-		</td>
-	</tr>
-	<tr id="CR-6">
-		<td>
-			CR-6
-		</td>
-		<td>Switch to another app to send the test app into the background. Go to Settings and check whether the test app has any services running while in the background. In Android 4.0 and higher, go to the Apps screen and find the app in the "Running" tab. In earlier versions, use "Manage Applications" to check for running services.
-		</td>
-	</tr>
-
-	
-	<tr  id="CR-7">
-		<td>
-			CR-7
-		</td>
-		<td>
-			Press the power button to put the device to sleep, then press the power button again to
-			awaken the screen.
-		</td>
-	</tr>
-	<tr id="CR-8">
-		<td>
-			CR-8
-		</td>
-		<td>
-			Set the device to lock when the power button is pressed. Press the power button to put the device to sleep, then press the power button again to
-			awaken the screen, then unlock the device.
-		</td>
-	</tr>
-	<tr id="CR-9">
-		<!-- Hardware features -->
-		<td>
-			CR-9
-		</td>
-		<td>
-			For devices that have slide-out keyboards, slide the keyboard in and out at least once.  For devices that have keyboard docks, attach the device to the keyboard dock.
-		</td>
-	</tr>
-	<tr id="CR-10">
-		<td>
-			CR-10
-		</td>
-		<td>
-			For devices that have an external display port, plug-in the external display.
-		</td>
-	</tr>
-	<tr id="CR-11">
-		<td>
-			CR-11
-		</td>
-		<td>Trigger and observe in the notications drawer all types of notifications that the app can display. Expand notifications where applicable (Android 4.1 and higher), and tap all actions offered.</td>
-	</tr>
-	<tr id="CR-12">
-		<td>
-			CR-12
-		</td>
-		<td>Examine the permissions requested by the app by going to Settings &gt; App Info.
-		</td>
-	</tr>
-	<tr id="tg3">
-	<td>Install on SD Card</td>
-		<td>
-			SD-1
-		</td>
-		<td>
-			<p style="margin-bottom:.5em;">Repeat <em>Core Suite</em> with app installed to <a href="{@docRoot}guide/topics/data/install-location.html">device SD card</a> (if supported by app).</p>
-			
-			<p style="margin-bottom:.25em;">To move the app to SD card, you can use Settings &gt; App Info &gt; Move to SD Card.</p>
-		</td>
-	</tr>
-	<tr id="tg3">
-			<td>Hardware acceleration</td>
-		<td>
-			HA-1
-		</td>
-		<td>
-			<p style="margin-bottom:.5em;">Repeat <em>Core Suite</em> with hardware acceleration enabled.</p>
-			
-			<p style="margin-bottom:.25em;">To force-enable hardware acceleration (where supported by device), add <code>hardware-accelerated="true"</code> to the <code>&lt;application&gt;</code> in the app manifest and recompile.</p>
-		</td>
-	</tr>
-	<tr id="tg3">
-			<td>Performance Monitoring</td>
-		<td>
-			PM-1
-		</td>
-		<td>
-		 <p style="margin-bottom:.5em;">Repeat <em>Core Suite</em> with StrictMode profiling enabled <a href="#strictmode">as described below</a>. <p style="margin-bottom:.25em;">Pay close attention to garbage collection and its impact on the user experience.</p>
-		</td>
-	</tr>
-	<tr  id="gp">
-		<td rowspan="3">Google Play</td>
-		<td>
-			GP-1
-		</td>
-		<td>
-			Sign into the <a href="https://play.google.com/apps/publish/">Developer Console</a> to review your developer profile, app description, screenshots, feature graphic, maturity settings, and user feedback. 
-		</td>
-	</tr>
-	<tr  id="GP-2">
-		<td>
-			GP-2
-		</td>
-		<td>
-			Download your feature graphic and screenshots and scale them down to match the display sizes on the devices and form factors you are targeting.
-		</td>
-	</tr>
-	<tr  id="GP-3">
-		<td>
-			GP-3
-		</td>
-		<td>
-			Review all graphical assets, media, text, code libraries, and other content packaged in the app or expansion file download.
-		</td>
-	</tr>
-	<tr  id="GP-4">
-	<td>Payments</td>
-		<td>
-			GP-4
-		</td>
-		<td>
-			Navigate to all screens of your app and enter all in-app purchase flows.
-		</td>
-</tr>
-
-</table>
-
-<h3 id="strictmode">
-Testing with StrictMode
-</h3>
-
-<p>For performance testing, we recommend enabling 
-{@link android.os.StrictMode} in your app
-and using it to catch operations on the main thread and other threads that could
-affect performance, network accesses, file reads/writes, and so on.</p>
-
-<p>You can set up a monitoring policy per thread using 
-{@link android.os.StrictMode.ThreadPolicy.Builder} and enable all supported monitoring in the
-<code>ThreadPolicy</code> using 
-{@link android.os.StrictMode.ThreadPolicy.Builder#detectAll()}.</p>
-
-<p>Make sure to enable <strong>visual notification</strong> of policy violations
-for the <code>ThreadPolicy</code> using {@link android.os.StrictMode.ThreadPolicy.Builder#penaltyFlashScreen() penaltyFlashScreen()}.</p>
diff --git a/docs/html/distribute/googleplay/quality/index.jd b/docs/html/distribute/googleplay/quality/index.jd
deleted file mode 100644
index ef537b1..0000000
--- a/docs/html/distribute/googleplay/quality/index.jd
+++ /dev/null
@@ -1,45 +0,0 @@
-page.title=App Quality
-@jd:body
-
-<p>App quality directly influences the long-term success of your app&mdash;in
-terms of installs, user rating and reviews, engagement, and user retention.
-Android users expect high-quality apps, even more so if they've spent money on
-them. At the same time, users enjoy and value apps that put a priority on
-continuous improvement. </p>
-
-<p>Before you publish an app on Google Play, it's important to make sure that
-your app meets the basic quality expectations of users, across all of the form
-factors and device types that the app is targeting. The documents in this
-section help you assess your app's fundamental quality and address any
-issues that you find. </p>
-
-<div class="vspace size-1">
-  &nbsp;
-</div>
-<div class="layout-content-row">
-  <div class="layout-content-col span-4">
-    <h4>
-      Core App Quality
-    </h4>
-    <p>
-      A set of core quality criteria that all Android apps should meet on all targeted devices.
-    </p><a href="{@docRoot}distribute/googleplay/quality/core.html">Learn more »</a>
-  </div>
-  <div class="layout-content-col span-4">
-    <h4>
-      Tablet App Quality
-    </h4>
-    <p>
-      A set recommendations for delivering the best possible experience to tablet users.
-    </p><a href="{@docRoot}distribute/googleplay/quality/tablet.html">Learn more »</a>
-  </div>
-  <div class="layout-content-col span-4">
-    <h4>
-      Improving App Quality
-    </h4>
-    <p>
-      Tips on continuously improving your app's quality, ratings, reviews, downloads, and engagement.
-    </p><a href="{@docRoot}distribute/googleplay/strategies/app-quality.html">Learn more
-    »</a>
-  </div>
-</div>
diff --git a/docs/html/distribute/googleplay/quality/tablet.jd b/docs/html/distribute/googleplay/quality/tablet.jd
deleted file mode 100644
index fe046d4..0000000
--- a/docs/html/distribute/googleplay/quality/tablet.jd
+++ /dev/null
@@ -1,969 +0,0 @@
-page.title=Tablet App Quality Checklist
-@jd:body
-
-<div id="qv-wrapper"><div id="qv">
-<h2>Checklist</h2>
-<ol>
-
-<li><a href="#core-app-quality">1. Test for Basic Tablet App Quality</a></li>
-<li><a href="#optimize-layouts">2. Optimize your layouts</a></li>
-<li><a href="#use-extra-space">3. Use the extra screen area</a></li>
-<li><a href="#use-tablet-icons">4. Use assets designed for tablets</a></li>
-<li><a href="#adjust-font-sizes">5. Adjust fonts and touch targets</a></li>
-<li><a href="#adjust-widgets">6. Adjust homescreen widgets</a></li>
-<li><a href="#offer-full-feature-set">7. Offer the app's full feature set</a></li>
-<li><a href="#android-versions">8. Target Android versions properly</a></li>
-<li><a href="#hardware-requirements">9. Declare dependencies properly</a></li>
-<li><a href="#support-screens">10. Declare tablet screens support</a></li>
-<li><a href="#google-play">11. Showcase your tablet UI</a></li>
-<li><a href="#google-play-best-practices">12. Follow publishing best practices</a></li>
-
-</ol>
-<h2>Testing</h2>
-<ol>
-<li><a href="#test-environment">Setting Up a Test Environment</a></li>
-</ol>
-</div></div>
-
-<p>Before you publish an app on Google Play, it's important to make sure that the app meets the basic expectations of tablet users through compelling features and an intuitive, well-designed UI. </p>
-
-<p>Tablets are a growing part of the Android installed base that offers new
-opportunities for <a
-href="{@docRoot}distribute/googleplay/spotlight/tablets.html">user engagement
-and monetization</a>. If your app is targeting tablet users, this document helps
-you focus on key aspects of quality, feature set, and UI that can have a
-significant impact on the app's success. Each focus area is given as checklist
-item, with each one comprising several smaller tasks or best practices.</p>
-
-<p>Although the checklist tasks below are numbered for convenience, 
-you can handle them in any order and address them to the extent that you feel
-is right for your app. In the interest of delivering the best possible product
-to your customers, follow the checklist recommendations
-to the greatest extent possible. </p>
-
-<p>As you move through the checklist, you'll find links to support resources
-that can help you address the topics raised in each task.</p>
-
-
-<h2 id="core-app-quality" style="margin-top:1.5em;">1. Test for basic tablet app quality</h2>
-
-<p>The first step in delivering a great tablet app experience is making sure
-that it meets the <em>core app quality criteria</em> for all of the devices
-and form factors that the app is targeting. For complete information, see the <a
-href="{@docRoot}distribute/googleplay/quality/core.html">Core App Quality Guidelines</a>. 
-</p>
-
-<p>
-  Before publishing, also ensure that your app passes several basic
-  technical checks and launch criteria, such as:
-</p>
-
-<ul>
-  <li><a href="#android-versions">Targets appropriate Android versions</a></li>
-  <li><a href="#hardware-requirements">Specifies any hardware dependencies properly</a></li>
-  <li><a href="#support-screens">Declares support for appropriate screens</a></li>
-  <li><a href="#use-extra-space">Uses all of the available screen space</a></li>
-  <li><a href="#google-play">Screenshots are uploaded to Google Play</a></li>
-</ul>
-
-<p>If your app is already uploaded to the Google Play Developer Console, you
-  can see how it is doing against these checks  
-  by visiting the <a href="#google-play-optimization-tips">Optimization
-  Tips page</a>.</p>
-
-
-<h2 id="optimize-layouts">2. Optimize your layouts for larger screens</h2>
-
-<p>Android makes it easy to develop an app that runs well on a wide range of
-device screen sizes and form factors. This broad compatibility works in your
-favor, since it helps you design a single app that you can distribute widely to
-all of your targeted devices. However, to give your users the best possible
-experience on each screen configuration &mdash; in particular on tablets
-&mdash; you need to optimize your layouts and other UI components for each
-targeted screen configuration. On tablets, optimizing your UI lets you take
-full advantage of the additional screen available, such as to offer new features,
-present new content, or enhance the experience in other ways to deepen user
-engagement.</p>
-
-<p>If you developed your app for handsets and now want to distribute it to
-tablets, you can start by making minor adjustments to your layouts, fonts, and
-spacing. In some cases &mdash; such as for 7-inch tablets or for a game with
-large canvas &mdash; these adjustments may be all
-you need to make your app look great. In other cases, such as for larger
-tablets, you can redesign parts of your UI to replace "stretched UI" with an
-efficient multipane UI, easier navigation, and additional content. </p>
-
-<p>Here are some suggestions:</p>
-
-<div style="width:390px;float:right;margin:1.5em;margin-top:0em;">
-<img src="{@docRoot}images/training/app-navigation-multiple-sizes-multipane-bad.png"
-style="width:390px;padding:4px;margin-bottom:0em;">
-<p class="image-caption" style="padding:0em .5em .5em 2em"><span
-style="font-weight:500;">Get rid of "stretched" UI</span>: On tablets, single-pane
-layouts lead to awkward whitespace and excessive line lengths. Use padding to
-reduce the width of UI elements and consider using multi-pane layouts.</p>
-</div>
-
-<ul>
-<li>Provide custom layouts as needed for <code>large</code> and
-<code>xlarge</code> screens. You can also provide layouts that are loaded based
-on the screen's <a href="{@docRoot}guide/practices/screens_support.html#NewQualifiers">shortest
-dimension</a> or the <a href="{@docRoot}guide/practices/screens_support.html#NewQualifiers">minimum
-available width and height</a>. </li>
-<li>At a minimum, customize dimensions such as font sizes, margins, spacing for
-larger screens, to improve use of space and content legibility. </li>
-<li>Adjust positioning of UI controls so that they are easily accessible to
-users when holding a tablet, such as toward the sides when in
-landscape orientation.</li>
-<li>Padding of UI elements should normally be larger on tablets than on handsets. A
-<a href="{@docRoot}design/style/metrics-grids.html#48dp-rhythm">48dp rhythm</a> (and a 16dp
-grid) is recommended.</li>
-<li>Adequately pad text content so that it is not aligned directly along screen edges.
-Use a minimum <code>16dp</code> padding around content near screen edges.</li>
-</ul>
-
-<p>In particular, make sure that your layouts do not appear "stretched"
-across the screen:</p>
-
-<ul>
-<li>Lines of text should not be excessively long &mdash; optimize for a maximum
-100 characters per line, with best results between 50 and 75.</li>
-<li>ListViews and menus should not use the full screen width.</li>
-<li>Use padding to manage the widths of onscreen elements or switch to a
-multi-pane UI for tablets (see next section).</li>
-</ul>
-
-<div class="rel-resources">
-  <h3>
-    Related resources
-  </h3>
-
-  <ul>
-    <li>
-      <a href=
-      "{@docRoot}design/style/metrics-grids.html">Metrics
-      and Grids</a>&mdash;Android Design document that explains how to create
-      layouts based on density-independent grids.
-    </li>
-
-    <li>
-      <a href=
-      "{@docRoot}design/style/devices-displays.html">Devices
-      and Displays</a>&mdash;Android Design document that explains how to
-      design a UI that works well on different devices and
-      screen sizes.
-    </li>
-
-    <li>
-      <a href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple
-      Screens</a>&mdash;Developer documentation that explains the details of
-      managing UI for best display on multiple screen sizes.
-    </li>
-
-    <li>
-      <a href=
-      "{@docRoot}guide/practices/screens_support.html#ConfigurationExamples">
-      Configuration examples</a>&mdash;Examples of how to declare layouts and
-      other resources for specific screen sizes.
-    </li>
-  </ul>
-</div>
-
-
-<h2 id="use-extra-space">3. Take advantage of extra screen area available on tablets</h2>
-
-<div style="width:290px;float:right;margin:1.5em;margin-bottom:0;margin-top:0;">
-<img src="{@docRoot}images/training/app-navigation-multiple-sizes-multipane-good.png"
-style="width:280px;padding:4px;margin-bottom:0em;">
-<p class="image-caption" style="padding:0em .5em .5em 1.5em"><span
-style="font-weight:500;">Multi-pane layouts</span> result in a better visual
-balance on tablet screens, while offering more utility and legibility.</p>
-</div>
-
-<p>Tablet screens provide significantly more screen real estate to your app,
-especially when in landscape orientation. In particular, 10-inch tablets offer a
-greatly expanded  area, but even 7-inch tablets give you more space for
-displaying content and engaging users. </p>
-
-<p>As you consider the UI of your app when running on tablets, make sure that it
-is taking full advantage of extra screen area available on tablets. Here are
-some suggestions:</p>
-
-<ul>
-<li>Look for opportunities to include additional content or use an alternative
-treatment of existing content.</li>
-<li>Use <a href="{@docRoot}design/patterns/multi-pane-layouts.html">multi-pane
-layouts</a> on tablet screens to combine single views into a compound view. This
-lets you use the additional screen area more efficiently and makes it easier for
-users to navigate your app. </li>
-<li>Plan how you want the panels of your compound views to reorganize when
-screen orientation changes.</li>
-
-<div style="width:490px;margin:1.5em auto 1.5em 0;">
-<div style="">
-<img src="{@docRoot}images/ui-ex-single-panes.png"
-style="width:490px;padding:4px;margin-bottom:0em;" align="middle">
-<img src="{@docRoot}images/ui-ex-multi-pane.png" style="width:490px;padding:4px;margin-bottom:0em;">
-<p class="image-caption" style="padding:.5em"><span
-style="font-weight:500;">Compound views</span> combine several single views from a
-handset UI <em>(above)</em> into a richer, more efficient UI for tablets
-<em>(below)</em>. </p>
-</div>
-</div>
-
-<li>While a single screen is implemented as an {@link android.app.Activity}
-subclass, consider implementing individual content panels as {@link
-android.app.Fragment} subclasses. This lets you
-maximize code reuse across different form factors and across screens that
-share content.</li>
-<li>Decide on which screen sizes you'll use a multi-pane UI, then provide the
-different layouts in the appropriate screen size buckets (such as
-<code>large</code>/<code>xlarge</code>) or minimum screen widths (such as
-<code>sw600dp</code>/<code>sw720</code>).</li>
-</ul>
-
-<div class="rel-resources">
-  <h3>
-    Related resources
-  </h3>
-
-  <ul>
-    <li>
-      <a href="{@docRoot}design/patterns/multi-pane-layouts.html">Multi-pane
-      Layouts</a>&mdash;Android Design guide for using multi-pane UI, including
-      examples of how to flatten navigation and integrate more content into
-      your tablet UI.
-    </li>
-
-    <li>
-      <a href=
-      "{@docRoot}training/design-navigation/multiple-sizes.html">Planning for Multiple
-      Touchscreen Sizes</a>&mdash;Android Training class that walks you through
-      the essentials of planning an intuitive, effective navigation for tablets
-      and other devices.
-    </li>
-
-    <li>
-      <a href="{@docRoot}training/multiscreen/index.html">Designing for
-      Multiple Screens</a>&mdash;Android Training class that walks you through
-      the essentials of planning an intuitive, effective navigation for tablets
-      and other devices.
-    </li>
-  </ul>
-</div>
-
-
-<h2 id="use-tablet-icons">4. Use Icons and other assets that are designed
-for tablet screens</h2>
-
-<p>To ensure your app looks its best, provide icons and other bitmap
-assets for each density in the range commonly supported by tablets. Specifically, you should
-design your icons for the action bar, notifications, and launcher according to the
-<a href="{@docRoot}design/style/iconography.html">Iconography</a> guidelines and
-provide them in multiple densities, so they appear at the appropriate size on all screens
-without blurring or other scaling artifacts.</p>
-
-<p class="table-caption"><strong>Table 1</strong>. Raw asset sizes for icon types.<table>
-<tr>
-<th>Density</th>
-<th>Launcher</th>
-<th>Action Bar</th>
-<th>Small/Contextual</th>
-<th>Notification</th>
-</tr>
-<tr>
-<td><code>mdpi</code></td>
-<td>48x48 px</td>
-<td>32x32 px</td>
-<td>16x16 px</td>
-<td>24x24 px</td>
-</tr>
-<tr>
-<td><code>hdpi</code></td>
-<td>72x72 px</td>
-<td>48x48 px</td>
-<td>24x24 px</td>
-<td>36x36 px</td>
-</tr>
-<tr>
-<td><code>tvdpi</code></td>
-<td><em>(use hdpi)</em></td>
-<td><em>(use hdpi)</em></td>
-<td><em>(use hdpi)</em></td>
-<td><em>(use hdpi)</em></td>
-</tr>
-<tr>
-<td><code>xhdpi</code></td>
-<td>96x96 px</td>
-<td>64x64 px</td>
-<td>32x32 px</td>
-<td>48x48 px</td>
-</tr>
-<tr>
-<td><code>xxhdpi</code></td>
-<td>144x144 px</td>
-<td>96x96 px</td>
-<td>48x48 px</td>
-<td>72x72 px</td>
-</tr>
-
-</table>
-
-<p>Your app should supply a version of each icon and bitmap asset that's optimized
-for <strong>at least one</strong> the following common tablet screen densities:</p>
-
-<ul>
-  <li><code>hdpi</code></li>
-  <li><code>xhdpi</code></li>
-  <li><code>xxhdpi</code></li>
-</ul>
-
-<p>Other tips:</p>
-
-<ul>
-<li>When possible, use vector shapes for your icon designs so you can scale them
-without loss of detail and edge crispness.</li>
-<li>Use density-specific <a
-href="{@docRoot}guide/topics/resources/providing-resources.html#AlternativeResources">
-resource qualifiers</a> to ensure that the proper icons are loaded for each screen density.</li>
-<li>Tablets and other large screen devices often request a launcher icon that is one density
-size larger than the device's actual density, so you should provide your launcher
-icon at the highest density possible. For example, if a tablet has an {@code xhdpi} screen,
-it will request the {@code xxhdpi} version of the launcher icon.</li>
-</ul>
-
-<div class="rel-resources">
-  <h3>
-    Related resources
-  </h3>
-
-  <ul>
-    <li>
-      <a href="{@docRoot}design/style/iconography.html">Iconography</a>&mdash;
-      Design guidelines and tips about how to create various types of icons.
-    </li>
-
-    <li>
-      <a href=
-      "{@docRoot}guide/topics/resources/providing-resources.html">Providing
-      Resources</a>&mdash;Developer documentation on how to provide
-      sets of layouts and drawable resources for specific ranges of device
-      screens.
-    </li>
-
-    <li>
-      <a href="{@docRoot}guide/practices/screens_support.html">Supporting
-      Multiple Screens</a>&mdash;API Guide documentation that
-      explains the details of managing UI for best display on multiple screen
-      sizes.
-    </li>
-
-    <li>
-      <a href=
-      "{@docRoot}training/basics/supporting-devices/screens.html">Supporting Different
-      Screens</a>&mdash;Android Training class that takes you
-      through the process of optimizing the user experience for different
-      screen sizes and densities.
-    </li>
-  </ul>
-</div>
-
-
-<h2 id="adjust-font-sizes">5. Adjust font sizes and touch targets for tablet screens</h2>
-
-<p>To make sure your app is easy to use on tablets, take some time to adjust the
-font sizes and touch targets in your tablet UI, for all of the screen
-configurations you are targeting. You can adjust font sizes through <a
-href="{@docRoot}guide/topics/ui/themes.html">styleable attributes</a> or <a
-href="{@docRoot}guide/topics/resources/more-resources.html#Dimension">dimension
-resources</a>, and you can adjust touch targets through layouts and bitmap
-drawables, as discussed above. </p>
-
-<p>Here are some considerations:</p>
-<ul>
-<li>Text should not be excessively large or small on tablet screen sizes and
-densities. Make sure that labels are sized appropriately for the UI elements they
-correspond to, and ensure that there are no improper line breaks in labels,
-titles, and other elements.</li>
-<li>The recommended touch-target size for onscreen elements is 48dp (32dp
-minimum) &mdash; some adjustments may be needed in your tablet UI. Read <a
-href="{@docRoot}design/style/metrics-grids.html">Metrics and
-Grids
-</a> to learn about implementation strategies to help most of your users. To
-meet the accessibility needs of certain users, it may be appropriate to use
-larger touch targets. </li>
-<li>When possible, for smaller icons, expand the touchable area to more than
-48dp using {@link android.view.TouchDelegate}
-or just centering the icon within the transparent button.</li>
-</ul>
-
-<div class="rel-resources">
-  <h3>
-    Related resources
-  </h3>
-
-  <ul>
-    <li>
-      <a href=
-      "{@docRoot}design/style/metrics-grids.html">Metrics
-      and Grids</a> &mdash;Android Design document that explains how to arrange
-      and size touch targets and other UI elements on the screen.
-    </li>
-
-    <li>
-      <a href="{@docRoot}design/style/typography.html">Typography</a>&mdash;Android
-      Design document that gives an overview of how to use typography in your
-      apps.
-    </li>
-
-    <li>
-      <a href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple
-      Screens</a>&mdash;Developer documentation that explains the details of
-      managing UI for best display on multiple screen sizes.
-    </li>
-
-    <li>
-      <a href="{@docRoot}training/multiscreen/screendensities.html">Supporting
-      Different Densities</a>&mdash;Android Training class that shows you how
-      to provide sets of layouts and drawable resources for specific ranges of
-      device screens.
-    </li>
-  </ul>
-</div>
-
-
-<h2 id="adjust-widgets">6. Adjust sizes of home screen widgets for tablet screens</h2>
-
-<p>If your app includes a home screen widget, here are a few points to consider
-to ensure a great user experience on tablet screens: </p>
-
-<ul>
-<li>Make sure that the widget's default height and width are set appropriately
-for tablet screens, as well as the minimum and maximum resize height and width.
-</li>
-<li>The widget should be resizable to 420dp or more, to span 5 or more home
-screen rows (if this is a vertical or square widget) or columns (if this is a
-horizontal or square widget). </li>
-<li>Make sure that 9-patch images render correctly.</li>
-<li>Use default system margins.</li>
-<li>Set the app's <code>targetSdkVersion</code> to 14 or higher, if
-possible.</li>
-</ul>
-
-<div class="rel-resources">
-  <h3>
-    Related resources
-  </h3>
-
-  <ul>
-    <li>
-      <a href="{@docRoot}guide/topics/appwidgets/index.html#MetaData">Adding the
-      AppWidgetProviderInfo Metadata</a> &mdash;API Guide that explains how to
-      set the height and width dimensions of a widget.
-    </li>
-
-    <li>
-      <a href="{@docRoot}guide/practices/ui_guidelines/widget_design.html">App Widget
-      Design Guidelines</a>&mdash;API Guide that provides best practices and
-      techniques for designing and managing the size of widgets.
-    </li>
-  </ul>
-</div>
-
-
-<h2 id="offer-full-feature-set">7. Offer the app's full feature set to tablet users</h2>
-
-<p>Let your tablet users experience the best features of your app. Here are
-some recommendations:</p>
-
-<ul>
-<li>Design your app to offer at least the same set of features on tablets as it does on
-handsets. </li>
-<li>In exceptional cases, your app might omit or replace certain features on
-tablets if they are not supported by the hardware or use-case of most tablets.
-For example:
-<ul>
-<li>If the handset uses telephony features but telephony is not available on the
-current tablet, you can omit or replace the related functionality.</li>
-<li>Many tablets have a GPS sensor, but most users would not normally carry
-their tablets while running. If your phone app provides functionality to let the
-user record a GPS track of their runs while carrying their phones, the app would not need to
-provide that functionality on tablets because the use-case is not
-compelling.</li>
-</ul>
-</li>
-<li>If you will omit a feature or capability from your tablet UI, make sure
-that it is not accessible to users or that it offers “graceful degradation”
-to a replacement feature (also see the section below on hardware features).</li>
-</ul>
-
-<h2 id="android-versions">8. Target Android versions properly</h2>
-
-<p>To ensure the broadest possible distribution to tablets, make sure that your
-app properly targets the Android versions that support tablets. Initial support for
-tablets was added in <a href="{@docRoot}about/versions/android-3.0.html">Android 3.0</a>
-(API level 11). Unified UI
-framework support for tablets, phones, and other devices was introduced in <a
-href="{@docRoot}about/versions/android-4.0.html">Android 4.0</a> (API level 14) and is
-supported in later versions.
-
-<p>You can set the app's
-range of targeted Android versions in the manifest file, in the
-<a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html"><code>&lt;uses-sdk&gt;</code></a> element. In most cases, you can target Android versions properly by setting the element's <code>targetSdkVersion</code> attribute to the highest API level available.</p>
-
-<p style="margin-bottom:.5em;">At a minimum, check the <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html"><code>&lt;uses-sdk&gt;</code></a>
-  element to make sure that:</p>
-
-      <ol style="list-style-type:lower-alpha;margin-top:0em;">
-        <li><code>targetSdkVersion</code> is declared with value 11 or higher (14 or higher is recommended), OR</li>
-        <li><code>minSdkVersion</code> is declared with value 11 or higher.</li>
-        <li>If a <code>maxSdkVersion</code> attribute is declared, it must have a value of 11 or higher. Note that, in general, the use of <code>maxSdkVersion</code> is <em>not recommended</em>.</li>
-</ol>
-
-<div class="rel-resources">
-<h3>
-  Related resources
-</h3>
-
-<ul>
-  <li>
-    <a href=
-    "{@docRoot}guide/topics/manifest/uses-sdk-element.html#ApiLevels">Android API
-    Levels</a>&mdash;Introduces API levels and how they relate to compatibility.
-    A reference of available API levels is included.
-  </li>
-  <li>
-    <a href="{@docRoot}training/basics/supporting-devices/platforms.html">Supporting Different Platform Versions</a>&mdash;Training class showing how to declare support for
-    minimum and target API levels in your app. 
-  </li>
-</ul>
-</div>
-
-<h2 id="hardware-requirements">9. Declare hardware feature dependencies properly</h2>
-
-<p>
-  Handsets and tablets typically offer slightly different hardware support for
-  sensors, camera, telephony, and other features. For example, many tablets are
-  available in a "Wi-Fi" configuration that does not include telephony support.
-</p>
-
-<p>
-  So that you can distribute a single APK broadly across your full customer
-  base of phones and tablets, make sure that your app doesn't declare
-  requirements for hardware features that aren't commonly available on tablets.
-  Instead, properly declare the hardware features as <em>not required</em> in the app
-  manifest, as described below.
-</p>
-
-<ul>
-<li>In your app manifest, locate any <a href="{@docRoot}guide/topics/manifest/uses-feature-element.html"><code>&lt;uses-feature&gt;</code></a>
-elements. In particular, look for hardware features that might not be
-available on some tablets, such as:
-
-<ul>
-<li><code>android.hardware.telephony</code></li>
-<li><code>android.hardware.camera</code> (refers to back camera), or</li>
-<li><code>android.hardware.camera.front</code></li>
-</ul></li>
-
-<li>Declare the <a href="{@docRoot}guide/topics/manifest/uses-feature-element.html"><code>&lt;uses-feature&gt;</code></a>
-elements as <em>not required</em> by including the <code>android:required=”false”</code>
-attribute.
-
-<p>
-  For example, here's the proper way to declare a dependency on
-  <code>android.hardware.telephony</code>, such that you can still
-  distribute the app broadly, even to devices that don't offer telephony:
-</p>
-
-<pre>&lt;uses-feature android:name="android.hardware.telephony" android:required="false" /&gt;</pre></li>
-
-<li>Similarly, check the manifest for <a href="/guide/topics/manifest/permission-element.html"><code>&lt;permission&gt;</code></a> elements that 
-<a href="/guide/topics/manifest/uses-feature-element.html#permissions">imply hardware
-feature requirements</a> that not be appropriate for tablets. If you find such
-permissions, make sure to explicitly declare a corresponding
-<code>&lt;uses-feature&gt;</code> element for the features and includes the
-<code>android:required=”false”</code> attribute.</li>
-</ul>
-
-
-<p>
-  After declaring hardware features as <em>not required</em>, make sure to test
-  your app on a variety of devices. The app should function normally when the
-  hardware features it uses are not available, and it should offer "graceful
-  degradation" and alternative functionality where appropriate.
-</p>
-
-<p>
-  For example, if an app normally uses GPS to set the location but GPS is not
-  supported on the device, the app could let the user set the location manually
-  instead. The app can check for device hardware capabilities at runtime and handle
-  as needed.
-</p>
-
-<div class="rel-resources">
-<h3>
-  Related resources
-</h3>
-
-<ul>
-  <li>
-    <a href=
-    "{@docRoot}guide/topics/manifest/uses-feature-element.html#permissions">Permissions
-    that Imply Feature Requirements</a>&mdash;A list of permissions that may
-    cause unwanted filtering if declared in your app's manifest.
-  </li>
-  <li>
-    <a href=
-    "{@docRoot}guide/topics/manifest/uses-feature-element.html"><code>&lt;uses-feature&gt;</code></a>&mdash;Description
-    and reference documentation for the <code>&lt;uses-feature&gt;</code>
-    manifest element.
-  </li>
-
-  <li>
-    <a href="{@docRoot}guide/topics/manifest/uses-feature-element.html#testing">Testing
-    the features required by your application</a>&mdash;Description of how to
-    determine the actual set of hardware and software requirements (explicit or
-    implied) that your app requires.
-  </li>
-</ul>
-</div>
-
-<h2 id="support-screens">10. Declare support for tablet screens</h2>
-
-<p>To ensure that you can distribute your app to a broad range of tablets, your app should
-declare support for tablet screen sizes in its manifest file, as follows:</p>
-
-<ul>
-  <li>A
-  <a href="{@docRoot}guide/topics/manifest/supports-screens-element.html"><code>&lt;supports-screens&gt;</code></a>
-  element, if declared, must not specify <code>android:largeScreens="false"</code>
-  or <code>android:xlargeScreens="false"</code>.</li>
-  <li>For apps targeting <code>minSdkVersion</code> value less than 13, a
-  <a href="{@docRoot}guide/topics/manifest/supports-screens-element.html"><code>&lt;supports-screens&gt;</code></a>
-  element must be declared with both <code>android:largeScreens="true"</code> and
-  <code>android:xlargeScreens="true"</code>.</li>
-</ul>
-
-<p>If the app declares a
-<a href="{@docRoot}guide/topics/manifest/compatible-screens-element.html"><code>&lt;compatible-screens&gt;</code></a>
-element in the manifest, the element should include attributes that specify
-<em>all of the size and density combinations for tablet screens</em> that the
-app supports. Note that, if possible, you should avoid using the
-<a href="{@docRoot}guide/topics/manifest/compatible-screens-element.html"><code>&lt;compatible-screens&gt;</code></a>
-element in your app.</p>
-
-<div class="rel-resources">
-  <h3>
-    Related resources
-  </h3>
-
-  <ul>
-    <li>
-      <a href=
-      "{@docRoot}guide/practices/screens_support.html#DeclaringScreenSizeSupport">Declaring
-      Screen Size Support</a>&mdash;Developer documentation that explains the
-      details of managing UI for best display on multiple screen sizes.
-    </li>
-  </ul>
-</div>
-
-
-<h2 id="google-play">11. Showcase your tablet UI in Google Play</h2>
-
-<p>
-  After you've done the work to create an rich, optimized UI for your tablet
-  app, make sure that you let your customers know about it! Here are some key
-  ways to promote your tablet app to users on Google Play.
-</p>
-
-<h4>
-  Upload screenshots of your tablet UI
-</h4>
-
-<p>
-  Tablet users want to know what your app is like on a tablet device, not on a
-  phone. If you developed a tablet app, make sure to upload screenshots
-  of your tablet UI to the Google Play Developer Console. Here are some guidelines:
-  </p>
-
-<ul style="margin-top:0;">
-  <li>Your screenshots should show the core functionality of your app, not a
-  startup or sign-in page. Wherever users will spend most of their time, that's
-  what you should show in your screenshots.
-  </li>
-
-  <li>Add screenshots taken on both 7-inch and 10-inch tablets.
-  </li>
-
-  <li>It's recommended that you add screenshots taken in both landscape and
-  portrait orientations, if possible.
-  </li>
-
-  <li>Use screen captures if possible. Avoid showing actual device hardware in your
-  screenshots.</li>
-
-  <li>The recommended resolution of your tablet screenshots is <strong>1280 x 720</strong>
-  or higher in each orientation.
-  </li>
-
-  <li>You can upload as many as 8 screenshots of your tablet UI for 7-inch tablets
-  and an additional 8 for 10-inch tablets.
-  </li>
-</ul>
-
-<h4>
-  Update your app description and release notes
-</h4>
-
-<ul>
-  <li>In your app description, make sure to highlight that your app offers
-  tablet-optimized UI and great features for tablet users. Consider adding some
-  detail about how your tablet UI works and why users will like it.
-  </li>
-
-  <li>Include information about tablet support in the app's release notes and
-  update information.
-  </li>
-</ul>
-
-<h4>
-  Update your promotional video
-</h4>
-
-<p>
-  Many users view an app's promotional video to get an idea of what the app is
-  like and whether they'll enjoy it. For tablet users, capitalize on this
-  interest by highlighting your app's tablet UI in your promotional video. Here
-  are some tips and guidelines:
-</p>
-
-<ul>
-  <li>Add one or more shots of your app running on a tablet. To engage with
-  tablet users most effectively, it's recommended that you promote your tablet
-  UI in approximately equal proportion to your phone UI.
-  </li>
-
-  <li>Show your tablet UI as early as possible in the video. Don't assume that
-  tablet users will wait patiently through a feature walkthrough on a phone UI.
-  Ideally, you should engage them immediately by showing the tablet UI within
-  the first 10 seconds, or at the same point that you introduce the phone UI.
-  </li>
-
-  <li>To make it clear that you are showing a tablet UI, include shots of your
-  app running on a hand-held tablet device.
-  </li>
-
-  <li>Highlight your app's tablet UI in the video's narrative or voiceover.
-  </li>
-</ul>
-
-<h4>
-  Feature your tablet UI in your promotional campaigns
-</h4>
-
-<p>
-  Make sure to let tablet users know about your tablet UI in your promotional
-  campaigns, web site, social posts, advertisements, and elsewhere. Here are
-  some suggestions:
-</p>
-
-<ul>
-  <li>Plan a marketing or advertising campaign that highlights the use of your
-  app on tablets.</li>
-
-  <li>Show your tablet app at its best in your promotional campaigns&mdash;use the <a href=
-  "{@docRoot}distribute/promote/device-art.html">Device Art Generator</a> to
-  quickly generate a high-quality promotional image of your app running on a
-  7-inch or 10-inch tablet, in the orientation of your choice, with or without
-  drop-shadow and screen glare. It's as simple as capture, drag, and drop.
-  </li>
-
-  <li>Include a Google Play badge in your online promotions to let users link
-  directly to your app's store listing. You can generate a badge in a variety
-  of languages using the <a href=
-  "{@docRoot}distribute/googleplay/promote/badges.html">Badge Generator</a>.
-  </li>
-</ul>
-
-<div class="rel-resources">
-  <h3>
-    Related resources
-  </h3>
-
-  <ul>
-    <li>
-      <a href="{@docRoot}distribute/googleplay/publish/preparing.html">Publishing
-      Checklist</a>
-      &mdash;Recommendations on how to prepare your app for publishing, test
-      it, and launch successfully on Google Play.
-    </li>
-
-    <li>
-      <a href="https://play.google.com/apps/publish/">Google Play
-      Developer Console</a>&mdash;The tools console for publishing
-      your app to Android users.
-    </li>
-    <li>
-      <a href=
-      "{@docRoot}distribute/googleplay/promote/badges.html">Google Play
-      Badge Generator</a>&mdash;Create "Get it on Google Play" badges for your
-      app in a variety of languages with a single click. 
-    </li>
-    <li>
-      <a href=
-      "{@docRoot}distribute/promote/device-art.html">Device Art
-      Generator</a>&mdash;Drag and drop tool that lets you instantly create production-
-      ready art showing your app running on a tablet device. 
-    </li>
-  </ul>
-</div>
-
-<h2 id="google-play-best-practices">12. Follow best practices for publishing in Google Play</h2>
-
-<p>Here are some best practices for delivering a successful tablet app on Google Play.</p>
-
-<h4 id="google-play-optimization-tips">Check out your app's Optimization Tips</h4>
-
-<p>The Google Play Developer Console now offers an Optimization Tips page that
-lets you quickly check how your app is doing against basic guidelines for tablet app
-distribution and quality. To visit the page, sign into the Developer Console,
-load the app from All Applications, and click Optimization Tips in
-the left navigation.</p>
-
-<div class="sidebox-wrapper">
-<div class="sidebox">
-<h2 style="line-height:1em;">How to send feedback</h2>
-
-<p>Please use the link below to send
-feedback or request a manual review of your Optimization Tips.</p>
-
-<p>Make sure to read the relevant sections of the Tablet App Quality
-Guidelines prior to sending feedback.</p>
-
-<p><strong><a href="https://support.google.com/googleplay/android-developer/contact/tabletq"
-target="_googleplay" style="white-space:nowrap">Designed for Tablets Contact Form &raquo;</a></strong></p>
-</div>
-</div>
-
-<p>The Developer Console creates your app's Optimization Tips page
-by running a series of checks to verify basic quality
-criteria. If it finds any issues, it alerts you to them as "To Do"
-items in the Optimization Tips page.</p>
-
-<p>If you've developed a tablet experience for your app, make sure
-to visit the Optimization Tips page to see how your app is doing
-against the basic checks.  If there are any issues listed, we
-recommend addressing them in your app and uploading a new binary for
-distribution, if needed. </p>
-
-<p>If the Optimization Tips page lists "To Do" issues that you feel don't
-apply to your app or affect its quality on tablets, please notify us
-using the <a href="https://support.google.com/googleplay/android-developer/contact/tabletq"
-target="_googleplay" style="white-space:nowrap">Designed for Tablets Contact Form &raquo;</a>. We
-will review your app and update your Optimization Tips page as
-appropriate.</p>
-
-
-<h4>Confirm the app's filtering</h4>
-
-<p>After you've uploaded the app to the <a href="https://play.google.com/apps/publish/">Developer Console</a>, check the APK's Supported Devices list to make sure that the app is not filtered from tablet devices that you want to target.</p>
-
-<h4>Distribute as a single APK</h4>
-
-<p>
-  It's recommended that you publish your app as a single APK for all screen
-  sizes (phones and tablets), with a single Google Play listing. This approach
-  has several important advantages.
-</p>
-
-<ul style="margin-top:.25em;">
-  <li>Easier for users to find your app from search, browsing, or promotions
-  </li>
-
-  <li>Easier for users to restore your app automatically if they get a new
-  device.
-  </li>
-
-  <li>Your ratings and download stats are consolidated across all devices.
-  </li>
-
-  <li>Publishing a tablet app in a second listing can dilute ratings for your
-  brand.
-  </li>
-</ul>
-
-<p>
-  If necessary, you can alternatively choose to deliver your app using <a href=
-  "{@docRoot}google/play/publishing/multiple-apks.html">Multiple APK Support</a>,
-  although in most cases using a single APK to reach all devices is strongly
-  recommended.
-</p>
-
-<div class="rel-resources">
-<h3>Related resources</h3>
-<ul>
-<li><a href="{@docRoot}distribute/googleplay/publish/preparing.html">Publishing
-      Checklist</a>&mdash;
-  Recommendations on how to prepare your app for publishing, test it, and launch
-  successfully on Google Play.</li>
-<li><a href="https://play.google.com/apps/publish/">Google Play Developer
-  Console</a>&mdash;The tools console for publishing your app to Android users.</li>
-</ul>
-</div>
-
-
-<h2 id="test-environment">Setting Up a Test Environment for Tablets</h2>
-
-<p>To assess the quality of your app on tablets &mdash; both for core app quality
-and tablet app quality &mdash; you need to set up a suitable
-hardware or emulator environment for testing. </p>
-
-<p>The ideal test environment would
-include a small number of actual hardware devices that represent key form
-factors and hardware/software combinations currently available to consumers.
-It's not necessary to test on <em>every</em> device that's on the market &mdash;
-rather, you should focus on a small number of representative devices, even using
-one or two devices per form factor.  The table below provides an overview of
-devices you could use for testing.</p>
-
-<p>If you are not able to obtain actual hardware devices for testing, you should
-<a href="{@docRoot}tools/devices/index.html">set up emulated devices (AVDs)</a>
-to represent the most common form factors and
-hardware/software combinations. See the table below for suggestions on the emulator
-configurations to use. </p>
-
-<p>To go beyond basic testing, you can add more devices, more form factors, or
-new hardware/software combinations to your test environment. For example, you
-could include mid-size tablets, tablets with more or fewer hardware/software
-features, and so on. You can also increase the number or complexity of tests
-and quality criteria. </p>
-
-<p class="table-caption"><strong>Table 1</strong>. A typical tablet test environment might
-include one or two devices from each row in the table below, with one of the
-listed platform versions, screen configurations, and hardware feature configurations.</p>
-
-<table>
-<tr>
-<th>Type</th>
-<th>Size</th>
-<th>Density</th>
-<th>Version</th>
-<th>AVD Skin</th>
-</tr>
-
-<tr>
-<td>7-inch tablet</td>
-<td><span style="white-space:nowrap"><code>large</code> or</span><br /><code>-sw600</code></td>
-<td><code>hdpi</code>,<br /><code>tvdpi</code></td>
-<td>Android 4.0+ (API level 14 and higher)</td>
-<td>WXGA800-7in</td>
-</tr>
-<tr>
-<td><span style="white-space:nowrap">10-inch</span> tablet</td>
-<td><span style="white-space:nowrap"><code>xlarge</code> or</span><br /><code>-sw800</code></td>
-<td><code>mdpi</code>,<br /><code>hdpi</code>,<br /><code>xhdpi</code></td>
-<td>Android 3.2+ (API level 13 and higher)</td>
-<td>WXGA800</td>
-</tr>
-</table>
\ No newline at end of file
diff --git a/docs/html/distribute/googleplay/spotlight/index.jd b/docs/html/distribute/googleplay/spotlight/index.jd
deleted file mode 100644
index fc2e162..0000000
--- a/docs/html/distribute/googleplay/spotlight/index.jd
+++ /dev/null
@@ -1,162 +0,0 @@
-page.title=Spotlight
-page.tags="videos, google play, monetize, inapp"
-meta.tags="stories, googleplay, monetizing, landing"
-page.image=/images/video-kiwi.jpg
-walkthru=0
-header.hide=0
-
-@jd:body
-
-
-<p>Android developers, their apps, and their successes with Android and Google Play. </p>
-
-<div id="Kiwi" style="background: #F0F0F0;
-            border-top: 1px solid #DDD;
-            padding: 0px 0 24px 0;
-            overflow: auto;
-            clear:both;
-            margin-bottom:40px;
-            margin-top:30px;">
-   <div style="padding:0 0 0 29px;">
-        <h4>Developer Story: Kiwi, Inc.</h4>
-          <img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
-            -moz-border-radius: 5px;
-            border-radius: 5px height:78px;
-            width: 78px;
-            float: left;
-            margin: 17px 20px 9px 0;" 
-            src="//lh4.ggpht.com/qUI-8MJy70l4qoVBR_sx-56ckR_m0R_ZXcJ1DiTYUR3R_owWzsCFTYkAk4p5DMnaSdY3=w124" >
-          <div style="width:700px;">
-          <p style="margin-top:26px;
-                    margin-bottom:12px;">
-          Android-first developer <a href="//play.google.com/store/apps/developer?id=Kiwi,+Inc." target="_android">Kiwi, Inc.</a> has had 5 titles in the top 25 grossing on Google Play, including <a href="https://play.google.com/store/apps/details?id=com.kiwi.shipwrecked" target="_android">Shipwrecked: Lost Island</a>, <a href="https://play.google.com/store/apps/details?id=com.kiwi.monsterpark" target="_android">Monsterama Park</a>, and <a href="https://play.google.com/store/apps/details?id=com.kiwi.mysteryestate" target="_android">Hidden Object: Mystery Estate</a>. Hear how Google Play helped them double revenue every six months with features like instant updates, staged rollouts, and more.</p>
-           </div>
-           <iframe style="float:left;
-             margin-right:24px;
-             margin-top:14px;" width="700" height="394" src=
-             "http://www.youtube.com/embed/WWArLD6nqrk?HD=1;rel=0;origin=developer.android.com;" frameborder="0" allowfullscreen>
-           </iframe>
-   </div>
-</div>
-<div style="background: #F0F0F0;
-            border-top: 1px solid #DDD;
-            padding: 0px 0 24px 0;
-            overflow: auto;
-            clear:both;
-            margin-bottom:40px;
-            margin-top:30px;">
-   <div style="padding:0 0 0 29px;">
-        <h4>Developer Story: Colopl</h4>
-          <img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
-            -moz-border-radius: 5px;
-            border-radius: 5px height:78px;
-            width: 78px;
-            float: left;
-            margin: 17px 20px 9px 0;" 
-            src="//lh3.ggpht.com/sx2ILNaXQYOsHfR91T5tUWGlfXE1FutHCBN02Fll6mi9gIaG6RZCGbeJMtIvOoegCPTh=w124" >
-          <div style="width:700px;">
-          <p style="margin-top:26px;
-                    margin-bottom:12px;">
-          The creators of Kuma The Bear, Japan-based <a href="https://play.google.com/store/apps/developer?id=COLOPL,+Inc." target="_android">Colopl</a>, talk about how Google Play and Android allowed them to grow their business to become one of the most profitable games publishers in APAC to date. </p>
-           </div>
-           <iframe style="float:left;
-             margin-right:24px;
-             margin-top:14px;" width="700" height="394" src=
-             "http://www.youtube.com/embed/CbpoZeQCNe4?HD=1;rel=0;origin=developer.android.com;" frameborder="0" allowfullscreen>
-           </iframe>
-   </div> 
-</div>
-
-<div style="background: #F0F0F0;
-            border-top: 1px solid #DDD;
-            padding: 0px 0 24px 0;
-            overflow: auto;
-            clear:both;
-            margin-bottom:40px;
-            margin-top:30px;">
-   <div style="padding:0 0 0 29px;">
-        <h4>Developer Story: redBus.in</h4>
-          <img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
-            -moz-border-radius: 5px;
-            border-radius: 5px height:78px;
-            width: 78px;
-            float: left;
-            margin: 17px 20px 9px 0;" src=
-            "//lh4.ggpht.com/kvI2XfzBPGBDASvxvP18MCCj7YPEmLcG4nh1BlYW4XzaW12gg3iXtcM2ZqDnAfLLB9ed=w124">
-          <div style="width:700px;">
-          <p style="margin-top:26px;
-                    margin-bottom:12px;">
-          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;
-             margin-top:14px;" width="700" height="394" src=
-             "http://www.youtube.com/embed/O8i4HUw7JYA?HD=1;rel=0;origin=developer.android.com;" frameborder="0" allowfullscreen>
-           </iframe>
-   </div> 
-</div>
-
-<div style="background: #F0F0F0;
-            border-top: 1px solid #DDD;
-            padding: 0px 0 24px 0;
-            overflow: auto;
-            clear:both;
-            margin-bottom:40px;
-            margin-top:30px;">
-   <div style="padding:0 0 0 29px;">
-        <h4>Developer Story: Smule</h4>
-          <img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
-            -moz-border-radius: 5px;
-            border-radius: 5px height:78px;
-            width: 78px;
-            float: left;
-            margin: 17px 20px 9px 0;" src=
-            "//lh6.ggpht.com/z5wl9PuHl9JfO54uefjRTUX70SuLY-1DRpPxQ5mg7XEDfnYhBDssh1RrPZjN1tbwzhg=w124">
-          <div style="width:700px;">
-          <p style="margin-top:26px;
-                    margin-bottom:12px;">
-          The creators of <a href="//play.google.com/store/apps/details?id=com.smule.autorap">AutoRap</a>, <a href="//play.google.com/store/apps/details?id=com.smule.magicpiano">Magic Piano</a>, and <a href="//play.google.com/store/apps/details?id=com.smule.songify">Songify</a> talk about their experiences launching on Android, the explosive global growth they’ve seen on Google Play, and some of the techniques they use to market and monetize their products effectively across the world.</p>
-           </div>
-           <iframe style="float:left;
-             margin-right:24px;
-             margin-top:14px;" width="700" height="394" src=
-             "http://www.youtube.com/embed/RRelFvc6Czo?HD=1;rel=0;origin=developer.android.com;" frameborder="0" allowfullscreen>
-           </iframe>
-   </div> 
-</div>
-
-<div style="background: #F0F0F0;
-            border-top: 1px solid #DDD;
-            padding: 0px 0 24px 0;
-            overflow: auto;
-            clear:both;
-            margin-bottom:-10px;
-            margin-top:30px;">
-   <div style="padding:0 0 0 29px;">
-        <h4>Developer Story: Robot Invader</h4>
-          <img alt="" class="screenshot thumbnail" style="-webkit-border-radius: 5px;
-            -moz-border-radius: 5px;
-            border-radius: 5px height:78px;
-            width: 78px;
-            float: left;
-            margin: 17px 20px 9px 0;" src=
-            "//g0.gstatic.com/android/market/com.robotinvader.knightmare/hi-256-0-9e08d83bc8d01649e167131d197ada1cd1783fb0">
-          <div style="width:700px;">
-          <p style="margin-top:26px;margin-bottom:12px;">Robot Invader chose 
-              Android and Google Play as the launch platform for their first game,<br /> 
-              <a data-g-event="Developers Page" data-g-label="Case Study Link" href=
-              "//play.google.com/store/apps/details?id=com.robotinvader.knightmare"><em>Wind-up
-              Knight</em></a>.
-           </p>
-           <p>
-              Hear from the developers how Android helped them reach millions of users 
-              and more than 100 device models with a single app binary, then iterate rapidly to ensure
-              a great user experience.
-           </p>
-           </div>
-           <iframe style="float:left;
-             margin-right:24px;
-             margin-top:14px;" width="700" height="394" src=
-             "http://www.youtube.com/embed/hTtlLiUTowY" frameborder="0" allowfullscreen></iframe>
-   </div> 
-</div>
\ No newline at end of file
diff --git a/docs/html/distribute/googleplay/start.jd b/docs/html/distribute/googleplay/start.jd
new file mode 100644
index 0000000..6dc397b
--- /dev/null
+++ b/docs/html/distribute/googleplay/start.jd
@@ -0,0 +1,163 @@
+page.title=Get Started with Publishing
+page.metaDescription=Start publishing on Google Play in minutes by registering for a developer account.
+meta.tags="publishing"
+page.tags="google play", "publishing", "register", "signup"
+page.image=/distribute/images/getting-started.jpg
+
+@jd:body
+
+<div class="top-right-float" style="margin-right:24px;margin-top:-18px">
+  <a href="https://play.google.com/apps/publish/"><img src=
+  "{@docRoot}images/gp-start-button.png"></a>
+</div>
+
+<p>
+  Start publishing on Google Play in minutes by:
+</p>
+
+<ul>
+  <li>Registering for a Google Play publisher account
+  </li>
+
+  <li>Setting up a Google Wallet Merchant Account, if you will sell apps or
+  in-app products.
+  </li>
+
+  <li>Exploring the <a href="https://play.google.com/apps/publish/">Google Play
+  Developer Console</a> and publishing tools.
+  </li>
+</ul>
+
+<p>
+  When you're ready, use the Start button to go to the Developer Console.
+</p>
+
+<div class="headerLine">
+  <h1>
+    Register for a Publisher Account
+  </h1>
+
+  <hr>
+</div>
+
+<div class="sidebox-wrapper" style="float:right;">
+  <div class="sidebox">
+    <h2>
+      Tips
+    </h2>
+
+    <ul>
+      <li>You need a Google account to register. You can create one during the
+      process.
+      </li>
+
+      <li>If you are an organization, consider registering a new Google account
+      rather than using a personal account.
+      </li>
+
+      <li>Review the <a href=
+      "https://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=138294">
+        developer countries</a> and <a href=
+        "https://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=150324">
+        merchant countries</a> where you can distribute and sell apps.
+      </li>
+    </ul>
+  </div>
+</div>
+
+<ol>
+  <li>Visit the <a href="https://play.google.com/apps/publish/">Google Play
+  Developer Console</a>.
+  </li>
+
+  <li>Enter basic information about your <strong>developer identity</strong>
+  &mdash; name, email address, and so on. You can modify this information
+  later.
+  </li>
+
+  <li>Read and accept the <strong>Developer Distribution Agreement</strong> for
+  your country or region. Note that apps and store listings that you publish on
+  Google Play must comply with the Developer Program Policies and US export
+  law.
+  </li>
+
+  <li>Pay a <strong>$25 USD registration fee</strong> using Google Wallet. If
+  you don't have a Google Wallet account, you can quickly set one up during the
+  process.
+  </li>
+
+  <li>When your registration is verified, you’ll be notified at the email
+  address you entered during registration.
+  </li>
+</ol>
+
+<div class="headerLine">
+  <h1 id="merchant-account">
+    Set Up a Google Wallet Merchant Account
+  </h1>
+
+  <hr>
+</div>
+
+<div class="figure" style="width:200px;">
+  <img src="{@docRoot}images/gp-start-wallet-icon.png">
+</div>
+
+<p>
+  If you want to sell priced apps, in-app products, or subscriptions, you’ll
+  need a Google Wallet Merchant Account. You can set one up at any time, but
+  first review the list of <a href=
+  "https://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&answer=150324">
+  merchant countries</a>.<br>
+  <br>
+  To set up a Google Wallet Merchant Account:<br>
+  <br>
+</p>
+
+<ol>
+  <li>
+    <strong>Sign in</strong> to your Google Play Developer Console at <a href=
+    "https://play.google.com/apps/publish/" target=
+    "_blank">https://play.google.com/apps/publish/</a>.
+  </li>
+
+  <li>Open <strong>Financial reports</strong> <img src=
+  "{@docRoot}images/distribute/console-reports.png"> on the side navigation.
+  </li>
+
+  <li>Click <strong>Setup a Merchant Account now</strong>.
+  </li>
+</ol>
+
+<p>
+  This takes you to the Google Wallet site; you'll need information about your
+  business to complete this step.
+</p>
+
+<div class="headerLine">
+  <h1>
+    Explore the Developer Console
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  When your registration is verified, you can sign in to your Developer
+  Console, which is the home for your app publishing operations and tools on
+  Google Play.
+</p>
+
+<div>
+  <img src="{@docRoot}images/gp-dc-home.png" class="border-img">
+</div>
+
+<div class="headerLine">
+<h1 id="related-resources">Related Resources</h1><hr />
+</div>
+
+<div class="resource-widget resource-flow-layout col-13"
+  data-query="collection:distribute/googleplay/gettingstarted"
+  data-sortOrder="-timestamp"
+  data-cardSizes="9x3"
+  data-maxResults="6"></div>
diff --git a/docs/html/distribute/googleplay/strategies/app-quality.jd b/docs/html/distribute/googleplay/strategies/app-quality.jd
deleted file mode 100644
index eb2cd2b..0000000
--- a/docs/html/distribute/googleplay/strategies/app-quality.jd
+++ /dev/null
@@ -1,121 +0,0 @@
-page.title=Improving App Quality After Launch
-@jd:body
-
-<div id="qv-wrapper">
-<div id="qv">
-<h2>Strategies</h2>
-<ol>
-<li><a href="#listen">Listen to Your Users</a></li>
-<li><a href="#stability">Improve Stability and Eliminate Bugs</a></li>
-<li><a href="#responsiveness">Improve UI Responsiveness</a></li>
-<li><a href="#usability">Improve Usability</a></li>
-<li><a href="#appearance">Professional Appearance and Aesthetics</a></li>
-<li><a href="#features">Deliver the Right Set of Features</a></li>
-<li><a href="#integrate">Integrate with the System and Third-Party Apps</a></li>
-<li><a href="#details">Pay Attention to Details</a></li>
-</ol>
-
-<h2>You Should Also Read</h2>
-<ol>
-<li><a href="{@docRoot}distribute/googleplay/quality/core.html">Core App Quality Guidelines</a></li>
-<li><a href="{@docRoot}distribute/googleplay/quality/tablet.html">Tablet App Quality Checklist</a></li>
-</ol>
-
-</div>
-</div>
-
-<p>
-With thousands of new apps being published in Google Play every week, it's important to look for any available way to get the most visibility and the highest ratings possible.  One way of improving your app's visibility in the ecosystem is by deploying well-targeted mobile advertising campaigns and cross-app promotions. Another time-tested method of fueling the impression-install-ranking cycle is simply: <em>improve the product</em>!</p>
-<p>
-A better app can go a very long way: a higher quality app will translate to higher user ratings, generally better rankings, more downloads, and higher retention (longer install periods). High-quality apps also have a much higher likelihood of getting some unanticipated positive publicity such as being featured in Google Play or getting social media buzz.</p>
-<p>
-The upside to having a higher-quality app is obvious. However, it's not always clear how to make an app "better".  This document looks at some of the key factors in app quality and ways of improving your app over time, after you've launched the app.</p>
-
-<h2 id="listen">Listen to Your Users</h2>
-<p>
-Most ways of measuring the "success" of an app are dependent on user behavior. User-related metrics such as number of downloads, daily active installs, retention rates, and so on highlight the importance of users. If you aren't doing so already, it's a good idea to start thinking of your app's quality as it relates to your users.</p>
-<p>
-The most obvious way to listen to users is by reading and addressing comments on your app in Google Play. Although the comments aren't always productive or constructive, some will provide valuable insight on aspects of your app that you may not have consciously considered before. It's important to remember that users have the opportunity to change their ratings and comments about an app as much as they'd like.</p>
-<p>
-One way to reach users and help them address their concerns is to set up your own support and discussion destination(s). There are some great support tools out there that can put you in touch with your users directly, from forums such as <a href="http://groups.google.com">Google Groups</a> to comprehensive customer support products and destinations. Once you get set up with such a tool, make sure to fill in the support link in your Google Play product details page &mdash; users do click through to these.</p>
-<p>
-Another way to better listen to your users is by having a public beta or trusted tester program. It's crucial to have some amount of real user testing before releasing something in Google Play. Fortunately, you can distribute your apps to users outside of Google Play via a website; this website can require a login or be publicly accessible&nbsp;&mdash;&nbsp;it's entirely up to you. Take advantage of this opportunity by offering your next planned update to some early adopters, before submitting to Google Play. You'll be surprised by how many little, yet impactful, improvements can come out of crowd-sourced, real-user testing.</p>
-
-
-<h2 id="stability">Improve Stability and Eliminate Bugs</h2>
-
-<p>
-The effect of overall app stability of ratings and user satisfaction is very well-known and there are many tools and techniques for testing and profiling your app on different devices and user scenarios.</p>
-<p>
-One noteworthy and yet relatively underused tool for catching stability issues such as crashes is the <a href="{@docRoot}tools/help/monkey.html">UI/Application Exerciser Monkey</a> (Monkey). Monkey will send random UI events to your app's activities, allowing you to trigger user flows that can uncover stability problems.</p>
-<p>
-Also, with the Google error-reporting features built into most Android devices, users now have a way to report application crashes to developers. The error reports show up in aggregate in the Google Play Developer Console. Make sure to read these reports often and act on them appropriately.</p>
-<p>
-Last, keep an external bug and feature request tracker and let users know how to find it. This will enable them to engage with the app at a closer level, by following features and bugs that affect them. User frustration with app problems can be effectively managed with diligent issue tracking and communication. Some of the community support tools listed above offer issue tracking features, and if your project is open source, most popular repository hosting sites will offer this as well.</p>
-
-<h2 id="responsiveness">Improve UI Responsiveness</h2>
-<p>
-One sure-fire way to lose your users is to give them a slow, unresponsive UI. Research has shown that <a href="http://googleresearch.blogspot.com/2009/06/speed-matters.html">speed matters</a>... for any interface, be it desktop, web, or mobile. In fact, the importance of speed is amplified on mobile devices since users often need their information on the go and in a hurry.</p>
-<p>
-You can improve your apps's UI responsiveness by moving long-running operations off the main thread to worker threads. Android offers built-in debugging facilities such as StrictMode for analyzing your app's performance and activities on the main thread. You can see more recommendations in <a href="http://www.youtube.com/watch?v=c4znvD-7VDA">Writing Zippy Android Apps</a>, a developer session from Google I/O 2010,</p>
-
-<div class="sidebox-wrapper">
-<div class="sidebox">
-<h3>More resources</h3>
-<ul>
-<li><a href="{@docRoot}design/index.html">Android Design</a></li>
-<li><a href="{@docRoot}guide/practices/performance.html">Designing for Performance</a></li>
-<li><a href="{@docRoot}guide/practices/responsiveness.html">Designing for Responsiveness</a>
-<li><a href="{@docRoot}guide/practices/seamlessness.html">Designing for Seamlessness</a>
-</li>
-</ul>
-</div></div>
-<p>
-A great way to improve UI performance is to minimize the complexity of your layouts. If you open up <a href="{@docRoot}tools/help/hierarchy-viewer.html">hierarchyviewer</a> and see that your layouts are more than 5 levels deep, it may be time to simplify your layout. Consider refactoring those deeply nested LinearLayouts into RelativeLayout. The impact of View objects is cumulative &mdash; each one costs about 1 to 2 KB of memory, so large view hierarchies can be a recipe for disaster, causing frequent VM garbage collection passes which block the main (UI) thread. You can learn more in <a href="http://www.youtube.com/watch?v=wDBM6wVEO70">World of ListView</a>, another session at Google I/O.</p>
-<p>
-Lastly, pointed out in the blog post <a href="http://android-developers.blogspot.com/2010/10/traceview-war-story.html">Traceview War Story</a>, tools like <a href="{@docRoot}tools/help/traceview.html">traceview</code> and <a href="{@docRoot}tools/help/ddms.html">ddms</a> can be your best friends in improving your app by profiling method calls and monitoring VM memory allocations, respectively.</p>
-
-
-<h2 id="usability">Improve Usability</h2>
-<p>
-In usability and in app design too, you should listen carefully to your users. Ask a handful of real Android device users (friends, family, etc.) to try out your app and observe them as they interact with it. Look for cases where they get confused, are unsure of how to proceed, or are surprised by certain behaviors. Minimize these cases by rethinking some of the interactions in your app, perhaps working in some of the <a href="http://www.youtube.com/watch?v=M1ZBjlCRfz0">user interface patterns</a> the Android UI team discussed at Google I/O.</p>
-
-<div class="sidebox-wrapper">
-<div class="sidebox">
-<p>
-As you are designing or evaluating your app's UI, make sure to read and become familiar with the <a href="/design/index.html">Android Design</a> guidelines. Included are many examples of UI patterns, styles, and building blocks, as well as tools for the design process.</p>
-</div></div>
-
-<p>
-In the same vein, two problems that can plague some Android user interfaces are small tap targets and excessively small font sizes. These are generally easy to fix and can make a big impact on usability and user satisfaction. As a general rule, optimize for ease of use and legibility, while minimizing, or at least carefully balancing, information density.</p>
-
-<p>
-Another way to incrementally improve usability, based on real-world data, is to implement <a href="http://code.google.com/mobile/analytics/docs/">Analytics</a> throughout your app to log usage of particular sections. Consider demoting infrequently used sections to the overflow menu in the <a href="{@docRoot}design/patterns/actionbar.html">Action bar</a>, or removing them altogether. For often-used sections and UI elements, make sure they're immediately obvious and easily accessible in your app's UI so that users can get to them quickly.</p>
-<p>
-Lastly, usability is an extensive and well-documented subject, with close ties to interface design, cognitive science, and other disciplines.</p>
-
-<h2 id="appearance">Professional Appearance and Aesthetics</h2>
-<p>
-There's no substitute for a real user interface designer&nbsp;&mdash;&nbsp;ideally one who's well-versed in mobile and Android, and ideally handy with both interaction and visual design. One popular venue to post openings for designers is <a href="http://jobs.smashingmagazine.com">jobs.smashingmagazine.com</a>, and leveraging social networks can also surface great talent.</p>
-<p>
-If you don't have the luxury of working with a UI designer, there are some ways in which you can improve your app's appearance yourself. First, get familiar with Adobe Photoshop, Adobe Fireworks, or some other raster image editing tool. Mastering the art of the pixel in these apps takes time, but honing this skill can help build polish across your interface designs. Also, master the resources framework by studying the framework UI assets and layouts and reading through the <a href="{@docRoot}guide/topics/resources/index.html">resources documentation</a>. Techniques such as 9-patches and resource directory qualifiers are somewhat unique to Android, and are crucial in building flexible yet aesthetic UIs.</p>
-<p>
-Before you get too far in designing your app and writing the code, make sure to visit the Android Design site and learn about the vision, the building blocks, and the tools of designing beautiful and inspiring user interfaces.</p>
-
-<h2 id="features">Deliver the Right Set of Features</h2>
-<p>
-Having the <em>right</em> set of features in your app is important. It's often easy to fall into the trap of feature-creep, building as much functionality into your app as possible. Providing instant gratification by immediately showing the most important or relevant information is crucial on mobile devices. Providing too much information can be as frustrating (or even more so) than not providing enough of it.</p>
-<p>
-Again, listen to your users by collecting and responding to feature requests. Be careful, though, to take feature requests with a grain of salt. Requests can be very useful in aggregate, to get a sense of what kinds of functionality you should be working on, but not every feature request needs to be implemented.</p>
-
-<h2 id="integrate">Integrate with the System and Third-Party apps</h2>
-<p>
-A great way to deliver a delightful user experience is to integrate tightly with the operating system. Features like <a href="{@docRoot}guide/topics/appwidgets/index.html">Home screen widgets</a>, <a href="{@docRoot}design/patterns/notifications.html">rich notifications</a>, <a href="{@docRoot}guide/topics/search/index.html">global search integration</a>, and {@link android.widget.QuickContactBadge Quick Contacts} are fairly low-hanging fruit in this regard. </p>
-
-<p>For some app categories, basic features like home screen widgets are par for the course. Not including them is a sure-fire way to tarnish an otherwise positive user experience. Some apps can achieve even tighter OS integration with Android's contacts, accounts, and sync APIs. </p>
-<p>
-Third-party integrations can provide even more user delight and give the user a feeling of device cohesiveness. It's also a really nice way of adding functionality to your app without writing any extra code (by leveraging other apps' functionalities). For example, if you're creating a camera app, you can allow users to edit their photos in another app before saving them to their collection, if they have that third-party application installed. More information on this subject is available in the Android Training class <a href="{@docRoot}training/basics/intents/index.html">Interacting with Other Apps</a>.</p>
-
-<h2 id="details">Pay Attention to Details</h2>
-<p>
-One particular detail to pay close attention to is your app's icon quality and consistency. Make sure your app icons (especially your launcher icon) are crisp and pixel-perfect at all resolutions, and follow the <a href="{@docRoot}guide/practices/ui_guidelines/icon_design.html">icon guidelines</a> as much as possible. If you're having trouble or don't have the resources to design the icons yourself, consider using the <a href="http://android-ui-utils.googlecode.com/hg/asset-studio/dist/index.html">Android Asset Studio</a> tool to generate a set.</p>
diff --git a/docs/html/distribute/googleplay/strategies/featuring.jd b/docs/html/distribute/googleplay/strategies/featuring.jd
deleted file mode 100644
index 4c4e67e..0000000
--- a/docs/html/distribute/googleplay/strategies/featuring.jd
+++ /dev/null
@@ -1,4 +0,0 @@
-page.title=Preparing for Featuring
-@jd:body
-
-<p>Placeholder...</p>
\ No newline at end of file
diff --git a/docs/html/distribute/googleplay/strategies/index.jd b/docs/html/distribute/googleplay/strategies/index.jd
deleted file mode 100644
index 3794bbf..0000000
--- a/docs/html/distribute/googleplay/strategies/index.jd
+++ /dev/null
@@ -1,33 +0,0 @@
-page.title=Success Strategies
-page.metaDescription=
-header.hide=1
-footer.hide=1
-
-@jd:body
-
-
-
-<style>
-#landing-graphic-container {
-  position: relative;
-}
-
-#text-overlay {
-  position: absolute;
-  left: 0;
-  top: 472px;
-  width: 280px;
-}
-</style>
-
-<div id="landing-graphic-container">
-  <div id="text-overlay">
-   Strategies for building ratings, improving reviews, monetizing, and more.  
-    <br><br>
-    <a href="/distribute/googleplay/promote/product-pages.html" class="landing-page-link">Preparing for Featuring</a>
-  </div>
-
-  <a href="{@docRoot}distribute/googleplay/promote/index.html">
-    <img src="{@docRoot}design/media/index_landing_page.png">
-  </a>
-</div>
\ No newline at end of file
diff --git a/docs/html/distribute/images/about-play-education.jpg b/docs/html/distribute/images/about-play-education.jpg
new file mode 100644
index 0000000..1fe6b2c
--- /dev/null
+++ b/docs/html/distribute/images/about-play-education.jpg
Binary files differ
diff --git a/docs/html/distribute/images/about-play.jpg b/docs/html/distribute/images/about-play.jpg
new file mode 100644
index 0000000..e62cb58
--- /dev/null
+++ b/docs/html/distribute/images/about-play.jpg
Binary files differ
diff --git a/docs/html/distribute/images/advertising.jpg b/docs/html/distribute/images/advertising.jpg
new file mode 100644
index 0000000..9625671
--- /dev/null
+++ b/docs/html/distribute/images/advertising.jpg
Binary files differ
diff --git a/docs/html/distribute/images/advertising.png b/docs/html/distribute/images/advertising.png
new file mode 100644
index 0000000..5dc0ed4
--- /dev/null
+++ b/docs/html/distribute/images/advertising.png
Binary files differ
diff --git a/docs/html/distribute/images/alt-distribution.jpg b/docs/html/distribute/images/alt-distribution.jpg
new file mode 100644
index 0000000..39c0514
--- /dev/null
+++ b/docs/html/distribute/images/alt-distribution.jpg
Binary files differ
diff --git a/docs/html/distribute/images/android-support-card.jpg b/docs/html/distribute/images/android-support-card.jpg
new file mode 100644
index 0000000..b1883c0
--- /dev/null
+++ b/docs/html/distribute/images/android-support-card.jpg
Binary files differ
diff --git a/docs/html/distribute/images/build-buzz.jpg b/docs/html/distribute/images/build-buzz.jpg
new file mode 100644
index 0000000..3f83a1a
--- /dev/null
+++ b/docs/html/distribute/images/build-buzz.jpg
Binary files differ
diff --git a/docs/html/distribute/images/core-quality-guidelines.jpg b/docs/html/distribute/images/core-quality-guidelines.jpg
new file mode 100644
index 0000000..d0c2479
--- /dev/null
+++ b/docs/html/distribute/images/core-quality-guidelines.jpg
Binary files differ
diff --git a/docs/html/distribute/images/create-listing.jpg b/docs/html/distribute/images/create-listing.jpg
new file mode 100644
index 0000000..befb936
--- /dev/null
+++ b/docs/html/distribute/images/create-listing.jpg
Binary files differ
diff --git a/docs/html/distribute/images/default.jpg b/docs/html/distribute/images/default.jpg
new file mode 100644
index 0000000..8050744
--- /dev/null
+++ b/docs/html/distribute/images/default.jpg
Binary files differ
diff --git a/docs/html/distribute/images/developer-console.jpg b/docs/html/distribute/images/developer-console.jpg
new file mode 100644
index 0000000..09f4a86
--- /dev/null
+++ b/docs/html/distribute/images/developer-console.jpg
Binary files differ
diff --git a/docs/html/distribute/images/ecommerce.jpg b/docs/html/distribute/images/ecommerce.jpg
new file mode 100644
index 0000000..0b2efdc
--- /dev/null
+++ b/docs/html/distribute/images/ecommerce.jpg
Binary files differ
diff --git a/docs/html/distribute/images/edu-guidelines.jpg b/docs/html/distribute/images/edu-guidelines.jpg
new file mode 100644
index 0000000..280dcfee
--- /dev/null
+++ b/docs/html/distribute/images/edu-guidelines.jpg
Binary files differ
diff --git a/docs/html/distribute/images/expand-into-new-markets.jpg b/docs/html/distribute/images/expand-into-new-markets.jpg
new file mode 100644
index 0000000..0f17f13
--- /dev/null
+++ b/docs/html/distribute/images/expand-into-new-markets.jpg
Binary files differ
diff --git a/docs/html/distribute/images/freemium.jpg b/docs/html/distribute/images/freemium.jpg
new file mode 100644
index 0000000..6919202
--- /dev/null
+++ b/docs/html/distribute/images/freemium.jpg
Binary files differ
diff --git a/docs/html/distribute/images/getting-started.jpg b/docs/html/distribute/images/getting-started.jpg
new file mode 100644
index 0000000..47f524a
--- /dev/null
+++ b/docs/html/distribute/images/getting-started.jpg
Binary files differ
diff --git a/docs/html/distribute/images/gp-app-practices.png b/docs/html/distribute/images/gp-app-practices.png
new file mode 100644
index 0000000..0afc4cb
--- /dev/null
+++ b/docs/html/distribute/images/gp-app-practices.png
Binary files differ
diff --git a/docs/html/distribute/images/gp-edu-apps-image.jpg b/docs/html/distribute/images/gp-edu-apps-image.jpg
new file mode 100644
index 0000000..8785db1
--- /dev/null
+++ b/docs/html/distribute/images/gp-edu-apps-image.jpg
Binary files differ
diff --git a/docs/html/distribute/images/gp-games-practices.png b/docs/html/distribute/images/gp-games-practices.png
new file mode 100644
index 0000000..e2b63c5
--- /dev/null
+++ b/docs/html/distribute/images/gp-games-practices.png
Binary files differ
diff --git a/docs/html/distribute/images/gp-optimize-card.jpg b/docs/html/distribute/images/gp-optimize-card.jpg
new file mode 100644
index 0000000..4c91f1c
--- /dev/null
+++ b/docs/html/distribute/images/gp-optimize-card.jpg
Binary files differ
diff --git a/docs/html/distribute/images/gpfe-faq.jpg b/docs/html/distribute/images/gpfe-faq.jpg
new file mode 100644
index 0000000..cf10a95
--- /dev/null
+++ b/docs/html/distribute/images/gpfe-faq.jpg
Binary files differ
diff --git a/docs/html/distribute/images/know-your-user.jpg b/docs/html/distribute/images/know-your-user.jpg
new file mode 100644
index 0000000..9336125
--- /dev/null
+++ b/docs/html/distribute/images/know-your-user.jpg
Binary files differ
diff --git a/docs/html/distribute/images/launch-checklist.jpg b/docs/html/distribute/images/launch-checklist.jpg
new file mode 100644
index 0000000..c571c9e
--- /dev/null
+++ b/docs/html/distribute/images/launch-checklist.jpg
Binary files differ
diff --git a/docs/html/distribute/images/localization-checklist.jpg b/docs/html/distribute/images/localization-checklist.jpg
new file mode 100644
index 0000000..26765fe
--- /dev/null
+++ b/docs/html/distribute/images/localization-checklist.jpg
Binary files differ
diff --git a/docs/html/distribute/images/payment-method.jpg b/docs/html/distribute/images/payment-method.jpg
new file mode 100644
index 0000000..a9f8b19
--- /dev/null
+++ b/docs/html/distribute/images/payment-method.jpg
Binary files differ
diff --git a/docs/html/distribute/images/play-education.jpg b/docs/html/distribute/images/play-education.jpg
new file mode 100644
index 0000000..8780993
--- /dev/null
+++ b/docs/html/distribute/images/play-education.jpg
Binary files differ
diff --git a/docs/html/distribute/images/premium.jpg b/docs/html/distribute/images/premium.jpg
new file mode 100644
index 0000000..210fddb
--- /dev/null
+++ b/docs/html/distribute/images/premium.jpg
Binary files differ
diff --git a/docs/html/distribute/images/subscription.jpg b/docs/html/distribute/images/subscription.jpg
new file mode 100644
index 0000000..9b6f112
--- /dev/null
+++ b/docs/html/distribute/images/subscription.jpg
Binary files differ
diff --git a/docs/html/distribute/images/tablet-guidelines-color.jpg b/docs/html/distribute/images/tablet-guidelines-color.jpg
new file mode 100644
index 0000000..ffb1a03
--- /dev/null
+++ b/docs/html/distribute/images/tablet-guidelines-color.jpg
Binary files differ
diff --git a/docs/html/distribute/images/tablet-guidelines.jpg b/docs/html/distribute/images/tablet-guidelines.jpg
new file mode 100644
index 0000000..b16b48c
--- /dev/null
+++ b/docs/html/distribute/images/tablet-guidelines.jpg
Binary files differ
diff --git a/docs/html/distribute/index.jd b/docs/html/distribute/index.jd
index 544fdff..da960ce 100644
--- a/docs/html/distribute/index.jd
+++ b/docs/html/distribute/index.jd
@@ -1,37 +1,21 @@
-page.title=Distribute Apps
+page.title=Distribute Your Apps
+page.viewport_width=970
+section.landing=true
 header.hide=1
+nonavpage=true
+page.metaDescription=The most visited store in the world for Android apps. Cloud-connected and always synced, it's never been easier for users to find and download your apps.
 
 @jd:body
-    
-    
-<div class="marquee">
-  <div class="madin-img" style="position:absolute;margin-left:42px;margin-top:76px;">
-    <img src="{@docRoot}images/home/google-play.png">
-  </div>
-  <div class="copy" style="position:relative;left:480px;width:360;">
-    <h1 style="margin-bottom:10px;">Your Apps on Google Play</h1>
-    <p>The most visited store in the world for Android apps.  Cloud-connected and always synced,
-    it's never been easier for users to find and download your apps.</p>
-    <p><a class="button" href="https://play.google.com/apps/publish/"
-      >Go to Developer Console &raquo;</a></p>
-  </div>
-</div>
 
-<div class="distribute-features col-13" style="clear:both;margin-top:246px;">
-  <ul>
-    <li><h5>Growth Engine</h5>
-    A billion downloads a month and growing. Get your apps in front of millions of users at Google's scale.<br />
-    <a href="{@docRoot}distribute/googleplay/about/visibility.html">Read More ›</a>
-    <li><h5>Build Your Business</h5> Sell your app in over 130 countries.  Flexible monetization options with in-app purchase, subscriptions, and more. <br />
-    <a href="{@docRoot}distribute/googleplay/about/monetizing.html">Read More ›</a></li>
-    <li class="last"><h5>Distribution Control</h5> Deliver your apps to the users you want, on the devices you want, on <em>your</em> schedule. <br />
-    <a href="{@docRoot}distribute/googleplay/about/distribution.html">Read More ›</a></li>
-  </ul>
-</div>
-
-
-
-    
-
-
+  <div class="resource-widget resource-carousel-layout col-16" 
+    style="height:420px;margin-top:20px;padding-top:0"
+    data-query="type:youtube+tag:googleplay+tag:developerstory+tag:featured, type:blog+tag:googleplay+tag:distribute+tag:featured"
+    data-sortOdrder="-timestamp"
+    data-maxResults="4"></div>
+  
+  <div class="resource-widget resource-flow-layout col-16"
+    data-query="collection:launch/static"
+    data-sortOrder=""
+    data-cardSizes="6x6,6x6,6x2x3,12x6,6x6,6x2x3,6x6,6x6,12x6,6x6"
+    data-maxResults="24"></div>
 
diff --git a/docs/html/distribute/monetize/ads.jd b/docs/html/distribute/monetize/ads.jd
new file mode 100644
index 0000000..40120c3
--- /dev/null
+++ b/docs/html/distribute/monetize/ads.jd
@@ -0,0 +1,114 @@
+page.title=Monetize with Ads
+page.metaDescription=Ads are a quick and easy way to incorporate a monetization option into both your free and paid apps.
+page.tags="monetizing", "free", "freemium", "ads"
+page.image=/distribute/images/advertising.png
+
+@jd:body
+
+<div class="figure">
+  <img src="{@docRoot}distribute/images/advertising.jpg" style="width:460px;">
+</div>
+
+<p>
+  In-app advertising offers a quick and easy way to incorporate a monetization
+  option into both your <a href=
+  "{@docRoot}distribute/monetize/freemium.html">freemium</a>, <a href=
+  "{@docRoot}distribute/monetize/premium.html">premium</a>, and <a href=
+  "{@docRoot}distribute/monetize/subscriptions.html">subscription</a> apps. </p>
+
+<p>Using <a href=
+  "http://www.google.com/ads/admob/monetize.html#subid=us-en-et-dac">AdMob</a>
+  and the <a href="{@docRoot}google/play-services/ads.html">Google
+  Mobile Ads SDK</a> included in Google Play Services, you’re able to add
+  advertising into your apps, with just a few lines of code.
+</p>
+
+<p>
+  When including ads in your apps you should consider:
+</p>
+
+<ul>
+  <li>
+    <p>
+      <strong>Placement within your apps</strong> &mdash; Well placed ads will
+      optimize your revenue by making it more likely that users will ‘click
+      through’. Poorly placed ads can result in low click-through rates, and in
+      the worse cases poor rating and users rapidly abandoning your apps. You
+      can get advice on how to best place ads from the developer training on
+      <a href=
+      "{@docRoot}training/monetization/ads-and-ux.html">using
+      ads</a>.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      <strong>Ad formats</strong> &mdash; Every app offers a different type of
+      experience for users, so it’s important to consider the format of ads
+      you’re using to ensure it’s compatible with the experience. While banner
+      ads may work well for a flashlight utility app, an immersive gaming app
+      may benefit more from a video interstitial. Mismatched ad formats may
+      negatively affect your users’ experience and ad revenue, so try to select
+      formats that fit well with the content and flow of your apps.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      <strong>Maximizing your performance</strong> &mdash; Ensure you’re optimizing
+      your advertising revenue by maximizing your CPMs <em>and</em> fill rate.
+      Often ad providers will cite very high CPMs but will have a low fill rate
+      that can severely decrease your effective CPM, so look at both of these
+      figures. Also consider using a <a href=
+      "https://support.google.com/admob/v2/answer/3063564?hl=en&amp;ref_topic=3063091#subid=us-en-et-dac">
+      mediation</a> solution if you’d like to use multiple ad providers in your
+      apps. Look for solutions that offer yield management or <a href=
+      "https://support.google.com/admob/v2/answer/3379794?hl=en&amp;ref_topic=3379793#subid=us-en-et-dac">
+      network optimization</a> features to serve the highest paying ad for each
+      impression.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      <strong>Exercising control options</strong> &mdash; A variety of ads promoting a
+      broad selection of other services or apps may show up within you apps.
+      Depending on your goals and the type of experience you want to provide
+      your users, it may make sense to <a href=
+      "https://support.google.com/admob/v2/answer/3150235?hl=enl#subid=us-en-et-dac">
+      block</a> certain advertisements from appearing. Some developers don’t
+      want apps in a similar category showing to their users, but some don’t
+      mind.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      <strong>Cross promoting your other apps</strong> &mdash; Ads can be used for
+      more than just earning revenue. Consider using <a href=
+      "https://support.google.com/admob/v2/answer/3210452?hl=en#subid=us-en-et-dac">
+      house ads</a> within your apps to create awareness and promote your
+      entire portfolio of apps. When launching new apps, an easy way to quickly
+      attract users is to promote directly to your existing customers.
+    </p>
+  </li>
+</ul>
+
+<p>
+  To start monetizing with ads sign up for <a href=
+  "http://www.google.com/ads/admob/#subid=us-en-et-dac">AdMob</a> and integrate
+  the <a href="https://developers.google.com/mobile-ads-sdk/download">Google
+  Mobile Ads SDK</a> into your apps. If you also need to manage direct deals
+  with advertisers, consider using <a href=
+  "http://www.google.com/doubleclick/publishers/small-business/index.html#subid=us-en-et-dac">
+  DoubleClick for Publishers Small Business</a>.
+</p>
+
+<div class="headerLine"><h1 id="related-resources">Related resources</h1><hr></div>
+
+<div class="resource-widget resource-flow-layout col-13"
+  data-query="collection:distribute/monetize/advertising"
+  data-sortOrder="-timestamp"
+  data-cardSizes="9x3"
+  data-maxResults="6"></div>
+
diff --git a/docs/html/distribute/monetize/ecommerce.jd b/docs/html/distribute/monetize/ecommerce.jd
new file mode 100644
index 0000000..b3f790d
--- /dev/null
+++ b/docs/html/distribute/monetize/ecommerce.jd
@@ -0,0 +1,59 @@
+page.title=E-commerce
+page.image=/distribute/images/ecommerce.jpg
+page.metaImage=With Instant Buy you can sell physical goods and services from your web pages.
+page.tags="monetizing", "physical goods", "wallet"
+@jd:body
+
+<div class="figure">
+  <img src="{@docRoot}images/gp-ecom-0.png" style="width:300px;">
+  <p class="img-caption">
+    Product Purchase with Instant Buy
+  </p>
+</div>
+
+<p>
+  With Google Wallet Instant Buy, you've the added flexibility of selling
+  physical goods and services, such as clothing or movie tickets, through your
+  apps using <a href=
+  "https://developers.google.com/wallet/instant-buy/">Instant Buy for
+  Android</a> in the US.
+</p>
+
+<p>
+  You can use this option where your app is the store-front for retail or
+  webtail operations. However, you can also combine it with your <a href=
+  "{@docRoot}distribute/monetize/premium.html">premium</a> and <a href=
+  "{@docRoot}distribute/monetize/freemium.html">freemium</a> apps by offering
+  related products.
+</p>
+
+<p>
+  Your customers purchase goods and services with any Google Wallet payment
+  method &mdash; credit card, gift card, or Wallet balance. Google Wallet
+  Instant Buy helps you minimize user data entry by enabling your payment flow
+  to retrieve information directly from the user’s wallet.
+</p>
+
+<p>
+  You also keep your existing payment infrastructure and leverage Google Wallet
+  to optimize your payment flow &mdash; users can make purchases in as a few as
+  two clicks and the flow is simplified with features to retrieve information
+  directly from the user’s wallet and intelligent auto-completion of addresses.
+  To get started, set up a <a href=
+  "{@docRoot}distribute/googleplay/start.html#merchant-account">Merchant
+  Account</a>.
+</p>
+
+<div class="headerLine clearfloat">
+  <h1 id="related-resources">
+    Related Resources
+  </h1>
+
+  <hr>
+</div>
+<div class="resource-widget resource-flow-layout col-13"
+  data-query="collection:distribute/monetize/ecommerce"
+  data-sortOrder="-timestamp"
+  data-cardSizes="9x3"
+  data-maxResults="6"></div>
+
diff --git a/docs/html/distribute/monetize/freemium.jd b/docs/html/distribute/monetize/freemium.jd
new file mode 100644
index 0000000..ec86d19
--- /dev/null
+++ b/docs/html/distribute/monetize/freemium.jd
@@ -0,0 +1,80 @@
+page.title=Monetize Freemium Apps
+page.image=/distribute/images/freemium.jpg
+page.metaDescription=Use Google Play In-app Billing and other tools to monetize your free apps.
+page.tags="in-app", "billing", "iap", "monetizing"
+@jd:body
+
+<p>
+  Users are more likely to download free apps and games compared to priced
+  ones. However, we provide you with a number of ways to monetize free apps,
+  using <a href="{@docRoot}google/play/billing/index.html">In-app
+  Billing</a>. With this tool you can sell digital goods that are:
+</p>
+
+<ul>
+  <li>Durable &mdash; once purchased the item will always be available to the
+  user, such as additional app features.
+  </li>
+
+  <li>Consumable &mdash; items that might be used progressively or expire after
+  a period of time, such as a game booster or news subscription.
+  </li>
+</ul>
+
+<p>
+  A basic approach is to offer a free download with limited features or full
+  features for a limited time. Then use an in-app purchase to unlock the full,
+  unlimited app.
+</p>
+
+<div class="center-img" style="width:620px">
+<div style="float:right; width:300px; padding-left:1em;">
+  <img src="{@docRoot}images/gp-freemium-1.jpg" class="border-img">
+  <p class="img-caption">
+  Consumable product purchase
+  </p>
+</div>
+
+<div style="width:300px;float:left;">
+  <img src="{@docRoot}images/gp-freemium-0.jpg" class="border-img">
+  <p class="img-caption">
+  Durable goods purchase
+  </p>
+</div>
+</div>
+
+<p class="clearfloat">
+  A more advanced approach is to offer a range of features and content items
+  through in-app purchases. For example, in games you can offer users new
+  levels, playing pieces, or other game features. In apps you can offer
+  features or functionality that enhance the user experience either by
+  extending existing features or offering new ones. Using this approach you can
+  generate a continuing revenue stream from each app install.
+</p>
+
+<p>
+  Any item offered as an in-app purchase can also be offered as a subscription.
+</p>
+
+<p>
+  To get started with In-app Billing you need to set-up a Google Wallet
+  <a href="{@docRoot}distribute/googleplay/start.html#merchant-account">Merchant
+  Account</a> from Developer Console. You then define <a href=
+  "{@docRoot}distribute/googleplay/developer-console.html#in-app-products">in-app
+  products</a> in the Developer Console, integrate the In-app Billing API into
+  your apps, and add the mechanisms to unlock features or deliver content.
+</p>
+
+<div class="headerLine">
+  <h1 id="related-resources">
+  Related Resources
+  </h1>
+
+  <hr>
+</div>
+
+<div class="resource-widget resource-flow-layout col-13"
+  data-query="collection:distribute/monetize/freemium"
+  data-sortOrder="-timestamp"
+  data-cardSizes="9x3,9x3,9x3,9x3,6x3,6x3"
+  data-maxResults="6"></div>
diff --git a/docs/html/distribute/monetize/index.jd b/docs/html/distribute/monetize/index.jd
new file mode 100644
index 0000000..7350a24
--- /dev/null
+++ b/docs/html/distribute/monetize/index.jd
@@ -0,0 +1,36 @@
+page.title=Monetize
+section.landing=true
+nonavpage=true
+
+@jd:body
+
+<p>
+  There are many ways to make money with your apps on Google Play, and we offer
+  a variety of tools to make it easy. Take advantage of Google Play’s
+  phenomenal growth by using one or more of the business models available.
+</p>
+
+<p>
+  To get started, set up your <a href=
+  "{@docRoot}distribute/googleplay/start.html#merchant-account">Merchant Account</a>
+  from your Developer Console. This will not only help you get paid, but also
+  help you track where your money is coming from.
+</p>
+
+<div class="dynamic-grid">
+
+  <div class="resource-widget resource-flow-layout landing col-16"
+    data-query="collection:distribute/monetize"
+    data-cardSizes="6x6"
+    data-maxResults="9">
+  </div>
+
+<h3>Related resources</h3>
+
+  <div class="resource-widget resource-flow-layout col-16"
+    data-query="tag:monetizing"
+    data-sortOrder="-timestamp"
+    data-cardSizes="6x3"
+    data-maxResults="6">
+  </div>
+</div>
diff --git a/docs/html/distribute/monetize/monetize_toc.cs b/docs/html/distribute/monetize/monetize_toc.cs
new file mode 100644
index 0000000..aeb6cf8
--- /dev/null
+++ b/docs/html/distribute/monetize/monetize_toc.cs
@@ -0,0 +1,47 @@
+<ul id="nav">
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/monetize/premium.html">
+            <span class="en">Premium</span></a>
+    </div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/monetize/freemium.html">
+            <span class="en">Freemium</span>
+          </a>
+    </div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/monetize/subscriptions.html">
+          <span class="en">Subscriptions</span>
+        </a
+    </div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/monetize/ecommerce.html">
+          <span class="en">E-commerce</span>
+        </a>
+    </div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/monetize/ads.html">
+          <span class="en">Ads</span>
+        </a>
+    </div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/monetize/payments.html">
+          <span class="en">Purchasing</span>
+        </a>
+    </div>
+  </li>
+
+</ul>
+
+
+<script type="text/javascript">
+<!--
+    buildToggleLists();
+    changeNavLang(getLangPref());
+//-->
+</script>
+
diff --git a/docs/html/distribute/monetize/payments.jd b/docs/html/distribute/monetize/payments.jd
new file mode 100644
index 0000000..37b4d44
--- /dev/null
+++ b/docs/html/distribute/monetize/payments.jd
@@ -0,0 +1,104 @@
+page.title=Convenient, Frictionless Purchasing
+page.image=/distribute/images/payment-method.jpg
+page.metaDescription=Users can purchase instantly with a choice of payment methods.
+page.tags="google play", "payments", "gift card"
+
+@jd:body
+
+<div class="figure">
+  <img src="{@docRoot}images/gp-start-wallet-icon.png" style="width:200px;">
+</div>
+
+<p>
+  Google Play makes it fast and easy for your customers to buy your products,
+  whether from a phone, a tablet, or a desktop computer. They can purchase
+  instantly with a streamlined, consistent purchasing process and convenient
+  payment methods.
+</p>
+
+<div class="headerLine">
+  <h1 id="dcb">
+  Direct Carrier Billing
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  Users pay by charging their monthly carrier bills . The benefit of Direct
+  Carrier Billing is that it opens up markets where credit cards are less
+  common, as purchases are charged to your customers’ monthly mobile phone
+  bills. This option is available to users in key markets
+  around the world. Many more will get the option in the months ahead.
+</p>
+
+<div class="headerLine">
+  <h1 id="credit">
+  Credit Cards
+  </h1>
+  <hr>
+</div>
+
+<p>
+  Users can pay using any credit card that they’ve registered in Google Play.
+  Credit Cards added to Google Play are stored in the user’s Google Wallet and
+  available for in-app purchases and instant buys too. To make it easy for
+  users to get started, registration is offered as a part of the initial device
+  setup process.
+</p>
+
+<div class="headerLine clearfloat">
+  <h1 id="gift-cards">
+  Google Play Gift Cards
+  </h1>
+
+  <hr>
+</div>
+
+<div class="figure">
+  <img src="{@docRoot}images/gp-payments-1.png">
+</div>
+
+<p>
+  Gift cards enable users to add value to their Google Play balance by entering
+  a unique code printed on a card purchased online or from major retailers.
+  More information gift cards can be found <a href=
+  "http://play.google.com/intl/en-US_us/about/giftcards/" target=
+  "_android">here</a>.
+</p>
+
+<div class="headerLine clearfloat">
+  <h1 id="balance">
+  Google Play Balance
+  </h1>
+
+  <hr>
+</div>
+
+<div class="figure">
+  <img src="{@docRoot}images/gp-balance.png">
+</div>
+
+<p>
+  Google Play balance, also known as stored value, is a stored account balance
+  in Google Play. Users can increase their balance by redeeming <a href=
+  "https://play.google.com/intl/en-US_us/about/giftcards/">gift cards</a> or by
+  earning rewards through the <a href=
+  "https://play.google.com/store/apps/details?id=com.google.android.apps.paidtasks&amp;hl=en">
+  Google Opinions Rewards app</a>, and they can use their balance to make
+  purchases of apps, games, or other content.
+</p>
+
+<p>
+  The payment methods available to users may vary based on location, carrier
+  network, and other factors.
+</p>
+ 
+<div class="headerLine clearfloat"><h1 id="related-resources">Related Resources</h1><hr></div>
+
+<div class="resource-widget resource-flow-layout col-13"
+  data-query="collection:distribute/monetize/paymentmethods"
+  data-sortOrder="-timestamp"
+  data-cardSizes="9x3"
+  data-maxResults="8"></div>
+
diff --git a/docs/html/distribute/monetize/premium.jd b/docs/html/distribute/monetize/premium.jd
new file mode 100644
index 0000000..b66cd03
--- /dev/null
+++ b/docs/html/distribute/monetize/premium.jd
@@ -0,0 +1,49 @@
+page.title=Monetize Premium Apps
+page.image=/distribute/images/premium.jpg
+page.metaDescription=Charging users to download your apps is a simple, convenient monetization model.
+page.tags="monetizing", "paid"
+
+@jd:body
+
+<div class="figure"><img src="{@docRoot}images/gp-premium-0.png" />
+<p class="img-caption" style="width:300px">Paid app</p>
+</div>
+<p>
+  Charging users to download your apps is a simple, convenient monetization
+  model. After creating your <a href=
+  "/distribute/googleplay/start.html#merchant-account">Merchant
+  Account</a>, you <a href=
+  "/distribute/googleplay/developer-console.html#selling-pricing-your-products">set prices for your
+  apps</a> in the Developer Console. You can optionally include advertising or use
+  <a href="{@docRoot}google/play/billing/index.html">In-app
+  Billing</a> to sell additional features or content.
+</p>
+
+<p>
+  This model could work well for any app or game, but might be particularly
+  relevant to those with extensive features or that address a narrow niche in
+  the market. Certain categories of apps, such as games for children, should be
+  monetized by paying for them up front instead of advertising or in-app
+  purchases.
+</p>
+
+<p>
+  However, this model may limit your apps monetization potential, particularly
+  in developing markets. You may be able to achieve greater revenue using the
+  <a href="{@docRoot}distribute/monetize/freemium.html">freemium</a>, <a href=
+  "{@docRoot}distribute/monetize/subscriptions.html">subscriptions</a> or
+  <a href="{@docRoot}distribute/monetize/ads.html">advertising</a> models.
+</p>
+
+<div class="headerLine clearfloat">
+  <h1>
+  Related Resources
+  </h1>
+  <hr>
+</div>
+
+<div class="resource-widget resource-flow-layout col-13"
+  data-query="collection:distribute/monetize/premium"
+  data-sortOrder="-timestamp"
+  data-cardSizes="9x3"
+  data-maxResults="6"></div>
\ No newline at end of file
diff --git a/docs/html/distribute/monetize/subscriptions.jd b/docs/html/distribute/monetize/subscriptions.jd
new file mode 100644
index 0000000..a838e30
--- /dev/null
+++ b/docs/html/distribute/monetize/subscriptions.jd
@@ -0,0 +1,71 @@
+page.title=Monetize with Subscriptions
+page.image=/distribute/images/subscription.jpg
+page.metaDescription=Sell subscriptions to your products to create continuing revenue streams.
+page.tags="in-app", "iap", "monetizing", "free", "trials"
+@jd:body
+
+<div class="figure">
+  <img src="{@docRoot}images/gp-subscription-0.jpg">
+  <p class="img-caption" style="width:300px;">
+  In-App Subscriptions
+  </p>
+</div>
+
+<p>
+  Subscriptions provide an excellent opportunity to create continuing revenue
+  streams. Subscriptions are similar to digital goods offered through <a href=
+  "{@docRoot}google/play/billing/index.html">In-app Billing</a> but made
+  available on a recurring monthly or annual basis.
+</p>
+
+<p>
+  When users purchase subscriptions in your apps, Google Play handles all
+  checkout details so your apps never have to directly process any financial
+  transactions. Google Play processes all payments for subscriptions through
+  Google Wallet, just as it does for standard in-app products and app
+  purchases. This ensures a consistent and familiar purchase flow for your
+  users and reduces cart abandonment rates.
+</p>
+
+<p>
+  At a basic level you can offer use of your apps or access to their content on
+  a subscription basis, using a <a href=
+  "{@docRoot}google/play/billing/billing_subscriptions.html#trials">free trial
+  subscription</a> to allow users to explore the apps or content.
+</p>
+
+<p>
+  A more advanced approach is to offer specific features or content items as
+  subscriptions within your apps. This way you can offer users basic or core
+  features or content for free or part of the initial purchase and extended
+  features or content as subscriptions. You can have multiple subscriptions
+  active in an app at any one time.
+</p>
+
+<p>
+  To get started with subscriptions you need to set-up a Google Wallet <a href=
+  "{@docRoot}distribute/googleplay/start.html#merchant-account">Merchant
+  Account</a> from the Developer Console. You then define subscriptions for
+  published or draft apps in the <a href=
+  "{@docRoot}distribute/googleplay/developer-console.html#in-app-billing">In-app
+  Products</a> section of the Developer Console, integrate the In-app Billing
+  API into your apps, and add the mechanisms to unlock subscribed features or
+  deliver content.
+</p>
+
+<div class="sidebox" style="width:400px;float:left;margin-left:0">
+  <p>
+  <strong>Tip:</strong> Due to some direct carrier billing limits, we
+  recommend monthly subscriptions. Annual subscriptions may exceed limits,
+  causing the purchase to be blocked and you to lose that revenue.
+  </p>
+</div>
+
+<div class="headerLine clearfloat"><h1 id="related-resources">Related Resources</h1><hr></div>
+
+<div class="resource-widget resource-flow-layout col-13"
+  data-query="collection:distribute/monetize/subscriptions"
+  data-sortOrder="-timestamp"
+  data-cardSizes="9x3"
+  data-maxResults="6"></div>
+
diff --git a/docs/html/distribute/open.jd b/docs/html/distribute/open.jd
deleted file mode 100644
index f9e9c3b..0000000
--- a/docs/html/distribute/open.jd
+++ /dev/null
@@ -1,107 +0,0 @@
-page.title=Open Distribution
-@jd:body
-
-<p>As an open platform, Android offers choice. You
-distribute your Android apps to users in any way you want, using any
-distribution approach or combination of approaches that meets your needs. 
-From publishing in an app marketplace to serving your apps from a web site or
-emailing them directly users, you are never locked into any
-particular distribution platform.</p>
-
-<p>The process for building and packaging your app for distribution is the same,
-regardless of how you will distribute your app. This saves you time and lets you
-automate parts of the process as needed. You can read <a 
-href="{@docRoot}tools/publishing/preparing.html">Preparing 
-for Release</a> for more information.</p>
-
-<p>The sections below highlight some of the alternatives for distributing
-your apps to users.</p>
-
-<h2 id="publishing-marketplace">Distributing through an App Marketplace</h2>
-
-<p>Usually, to reach the broadest possible audience, you would distribute your
-apps through a marketplace, such as Google Play.</p>
-
-<p>Google Play is the premier marketplace for Android apps and is particularly
-useful if you want to distribute your applications to a large global audience.
-However, you can distribute your apps through any app marketplace you want or
-you can use multiple marketplaces.</p>
-
-<h2 id="publishing-email">Distributing your application through email</h2>
-
-<div class="figure" style="width:246px">
-  <img src="{@docRoot}images/publishing/publishing_via_email.png"
-       alt="Screenshot showing the graphical user interface users see when you send them an app"
-       style="width:240px;" />
-  <p class="img-caption">
-    <strong>Figure 1.</strong> Users can simply click <strong>Install</strong> when you send them
-    an application via email.
-  </p>
-</div>
-
-<p>The easiest and quickest way to release your application is to send it to users through
-email. To do this, you prepare your application for release and then attach it to an email
-and send it to a user. When users open your email message on their Android-powered device,
-the Android system will recognize the APK and display an <strong>Install Now</strong>
-button in the email message (see figure 1). Users can install your application by touching the
-button.</p>
-
-<p class="note"><strong>Note:</strong> The <strong>Install Now</strong> button
-shown in Figure 1 appears only if users have configured their device to allow
-installation from <a href="#unknown-sources">unknown sources</a> and have opened your 
-email with the native Gmail application.</p>
-
-<p>Distributing applications through email is convenient if you are sending your application to
-only a few trusted users, but it provides few protections from piracy and unauthorized
-distribution; that is, anyone you send your application to can simply forward it to someone else.</p>
-
-<h2 id="publishing-website">Distributing through a web site</h2>
-
-<p>If you do not want to release your app on a marketplace like Google Play, you
-can make the app available for download on your own website or server, including
-on a private or enterprise server. To do this, you must first prepare your
-application for release in the normal way. Then all you need to do is host the
-release-ready APK file on your website and provide a download link to users.
-</p>
-
-<p>When users browse to the download link from their Android-powered devices,
-the file is downloaded and Android system automatically starts installing it on
-the device. However, the installation process will start automatically only if
-users have configured their Settings to allow the installation of apps from
-<a href="#unknown-sources">unknown sources</a>.</p>
-
-<p>Although it is relatively easy to release your application on your own
-website, it can be inefficient. For example, if you want to monetize your
-application you will have to process and track all financial transactions
-yourself and you will not be able to use Google Play's <a
-href="{@docRoot}google/play/billing/index.html">In-app Billing service</a>
-to sell in-app products. In addition, you will not be able to use the <a
-href="{@docRoot}google/play/licensing/index.html">Licensing service</a> to
-help prevent unauthorized installation and use of your application.</p>
-
-
-<h2 id="unknown-sources">User Opt-In for Apps from Unknown Sources</h2>
-
-<div class="figure" style="width:246px;margin-top:0;">
-  <img src="{@docRoot}images/publishing/publishing_unknown_sources_sm.png"
-       alt="Screenshot showing the setting for accepting download and install of
-       apps from unknown sources." style="width:240px;" />
-  <p class="img-caption">
-    <strong>Figure 2.</strong> Users must enable the <strong>Unknown sources</strong>
-    setting before they can install apps not downloaded from Google Play. 
-  </p>
-</div> 
-
-<p>Android protects users from inadvertent download and install of apps from
-locations other than Google Play (which is trusted). It blocks such installs
-until the user opts-in <strong>Unknown sources</strong> in
-Settings&nbsp;<strong>&gt;</strong>&nbsp;Security, shown in Figure 2. To allow
-the installation of applications from other sources, users need to enable the
-Unknown sources setting on their devices, and they need to make this
-configuration change <em>before</em> they download your application to their
-devices.</p> 
-
-<p class="note">Note that some network providers do not allow users to install
-applications from unknown sources.</p>
-
-
diff --git a/docs/html/distribute/googleplay/spotlight/games.jd b/docs/html/distribute/stories/games.jd
similarity index 91%
rename from docs/html/distribute/googleplay/spotlight/games.jd
rename to docs/html/distribute/stories/games.jd
index 1fbc03f..1a482b1 100644
--- a/docs/html/distribute/googleplay/spotlight/games.jd
+++ b/docs/html/distribute/stories/games.jd
@@ -1,6 +1,7 @@
 page.title=Developer Stories: Google Play Game Services
-walkthru=0
-header.hide=0
+meta.tags="google play, developer story, games, global"
+page.image=/images/distribute/glu-ew-gpgames.jpg
+page.metaDescription=How gaming studios are using Google Play game services to deliver new gaming experiences for their users.
 
 @jd:body
 
@@ -25,7 +26,7 @@
   width: 78px;
   float: left;
   margin: 12px 20px 9px 20px;"
-  src="//lh6.ggpht.com/_UOay5HBxf077suKYzmikU2IbnYOJub3X0inz-LoUsVh4TX758BEyArjoR7owXijkAA=w124">
+  src="http://lh6.ggpht.com/_UOay5HBxf077suKYzmikU2IbnYOJub3X0inz-LoUsVh4TX758BEyArjoR7owXijkAA=w124">
 
 <div style="list-style: none;height:100%;
   float: right;
@@ -49,7 +50,7 @@
     
     <div style="padding:.5em 0 0 1em;">
       <a href="https://play.google.com/store/apps/details?id=com.concretesoftware.pbachallenge_androidmarket&hl=en">
-       <img alt="Android app on Google Play" src="//developer.android.com/images/brand/en_generic_rgb_wo_45.png" />
+       <img alt="Android app on Google Play" src="{@docRoot}images/brand/en_generic_rgb_wo_45.png" />
       </a>
     </div>
 </div>
@@ -102,7 +103,7 @@
   width: 78px;
   float: left;
   margin: 12px 20px 30px 20px;"
-  src="//lh4.ggpht.com/Q7mQJsdhulW4_s039R9aaRhQkGnyzLkhF00j5EnyhHOivijnyi7P7b5A8qG0xk1r-jQ=w124">
+  src="http://lh4.ggpht.com/Q7mQJsdhulW4_s039R9aaRhQkGnyzLkhF00j5EnyhHOivijnyi7P7b5A8qG0xk1r-jQ=w124">
           
 <div style="list-style: none;height:100%;
   float: right;
@@ -126,7 +127,7 @@
 
     <div style="padding:.5em 0 0 1em;">
       <a href="https://play.google.com/store/apps/details?id=com.glu.ewarriors2">
-        <img alt="Android app on Google Play" src="//developer.android.com/images/brand/en_generic_rgb_wo_45.png" />
+        <img alt="Android app on Google Play" src="{@docRoot}images/brand/en_generic_rgb_wo_45.png" />
       </a>
     </div>
 </div>
@@ -176,7 +177,7 @@
   width: 78px;
   float: left;
   margin: 12px 20px 9px 20px;" src=
-  "https://lh3.ggpht.com/dTUrKLffqXHJtPuIlp8fjDhROuzrTcpidbNFprugR65hMrPLX7Omd8SGop0xMXXKzcw=w124">
+  "http://lh3.ggpht.com/dTUrKLffqXHJtPuIlp8fjDhROuzrTcpidbNFprugR65hMrPLX7Omd8SGop0xMXXKzcw=w124">
   
 <div style="list-style: none;height:100%;
   float: right;
@@ -202,7 +203,7 @@
 
   <div style="padding:.5em 0 0 1em;">
     <a href="https://play.google.com/store/apps/details?id=com.vectorunit.red">
-      <img alt="Android app on Google Play" src="//developer.android.com/images/brand/en_generic_rgb_wo_45.png" />
+      <img alt="Android app on Google Play" src="{@docRoot}images/brand/en_generic_rgb_wo_45.png" />
     </a>
   </div>
 </div>
diff --git a/docs/html/distribute/stories/index.jd b/docs/html/distribute/stories/index.jd
new file mode 100644
index 0000000..ca7647d
--- /dev/null
+++ b/docs/html/distribute/stories/index.jd
@@ -0,0 +1,13 @@
+page.title=Developer Stories
+section.landing=true
+page.metaDescription=Android developers, their apps, and their successes with Android and Google Play.
+
+@jd:body
+
+<p>Android developers, their apps, and their successes with Android and Google Play.</p>
+
+<div class="resource-widget resource-flow-layout col-13"
+    data-query="type:youtube+tag:developerstory"
+    data-sortOrder="-timestamp"
+    data-cardSizes="18x12"
+    data-maxResults="32"></div>
diff --git a/docs/html/distribute/googleplay/spotlight/localization.jd b/docs/html/distribute/stories/localization.jd
similarity index 95%
rename from docs/html/distribute/googleplay/spotlight/localization.jd
rename to docs/html/distribute/stories/localization.jd
index ae5993d..d6e6ccf 100644
--- a/docs/html/distribute/googleplay/spotlight/localization.jd
+++ b/docs/html/distribute/stories/localization.jd
@@ -1,6 +1,8 @@
 page.title=Developer Stories: Localization in Google Play
-walkthru=0
-header.hide=0
+meta.tags="google play, developer story, localization, global"
+page.tags="stories", "video", "case study"
+page.image=/images/distribute/zombie-ragdoll-n5-land.jpg
+page.metaDescription=Hear from Android developers who have successfully used the Google Play App Translation Service.
 
 @jd:body
 
@@ -65,7 +67,7 @@
     <div style="padding:.5em 0 0 1em;">
       <a href="https://play.google.com/store/apps/details?id=com.rvappstudios.zombieragdoll">
         <img alt="Android app on Google Play"
-         src="//developer.android.com/images/brand/en_generic_rgb_wo_45.png" />
+         src="{@docRoot}images/brand/en_generic_rgb_wo_45.png" />
       </a>
 
     </div>
@@ -177,7 +179,7 @@
     <div style="padding:.5em 0 0 1em;">
       <a href="https://play.google.com/store/apps/details?id=com.unearby.sayhi">
         <img alt="Android app on Google Play"
-         src="//developer.android.com/images/brand/en_generic_rgb_wo_45.png" />
+         src="{@docRoot}images/brand/en_generic_rgb_wo_45.png" />
       </a>
 
     </div>
@@ -262,7 +264,7 @@
     <div style="padding:.5em 0 0 1em;">
       <a href="https://play.google.com/store/apps/details?id=com.rvappstudios.zombieragdoll">
         <img alt="Android app on Google Play"
-         src="//developer.android.com/images/brand/en_generic_rgb_wo_45.png" />
+         src="{@docRoot}images/brand/en_generic_rgb_wo_45.png" />
       </a>
     </div>
   </div>
diff --git a/docs/html/distribute/stories/stories_toc.cs b/docs/html/distribute/stories/stories_toc.cs
new file mode 100644
index 0000000..944dabe
--- /dev/null
+++ b/docs/html/distribute/stories/stories_toc.cs
@@ -0,0 +1,34 @@
+<ul id="nav">
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/stories/index.html">
+            <span class="en">Videos</span></a>
+    </div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/stories/localization.html">
+            <span class="en">Going Global</span></a>
+    </div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/stories/games.html">
+            <span class="en">Games</span>
+          </a>
+    </div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/stories/tablets.html">
+          <span class="en">Tablets</span>
+        </a>
+    </div>
+  </li>
+
+</ul>
+
+
+<script type="text/javascript">
+<!--
+    buildToggleLists();
+    changeNavLang(getLangPref());
+//-->
+</script>
+
diff --git a/docs/html/distribute/googleplay/spotlight/tablets.jd b/docs/html/distribute/stories/tablets.jd
similarity index 91%
rename from docs/html/distribute/googleplay/spotlight/tablets.jd
rename to docs/html/distribute/stories/tablets.jd
index 7a98755..771fa52 100644
--- a/docs/html/distribute/googleplay/spotlight/tablets.jd
+++ b/docs/html/distribute/stories/tablets.jd
@@ -1,11 +1,12 @@
 page.title=Developer Stories: The Opportunity of Android Tablets
-walkthru=0
-header.hide=0
+meta.tags="google play, developer story, journal, tablets, pure"
+pdage.metaDescription=Developers are investing in a full tablet experience for their apps and seeing those investments pay off big.
+page.image=/images/distribute/rememberthemilk.png
 
 @jd:body
 
 
-<p>More and more, developers are investing in a full tablet experience
+<p>"More" and more, developers are investing in a full tablet experience
 for their apps and are seeing those investments pay off big. The increased
 screen area on tablets opens up a world of possibilities, allowing for more
 engagement with the user &mdash; which can mean an increase in usage as well as
@@ -27,7 +28,7 @@
             width: 78px;
             float: left;
             margin: 12px 20px 9px 20px;" src=
-            "//lh3.ggpht.com/xmnal18taauP2mjQFEhr1PhcItQ_W32IRuaD86IoL2U_4E-mfeKiliKtkISgOuA6Ln9n=w124">
+            "http://lh3.ggpht.com/xmnal18taauP2mjQFEhr1PhcItQ_W32IRuaD86IoL2U_4E-mfeKiliKtkISgOuA6Ln9n=w124">
           
   <div style="list-style: none;height:100%;
   float: right;
@@ -40,7 +41,7 @@
     
     
     <ul>
-      <li><a href="//play.google.com/store/apps/details?id=com.rememberthemilk.MobileRTM">Remember The Milk</a></li>
+      <li><a href="http://play.google.com/store/apps/details?id=com.rememberthemilk.MobileRTM">Remember The Milk</a></li>
       <li>A feature-packed to-do list app; never forget the milk (or anything else) again</li>
     </ul>
 
@@ -53,9 +54,9 @@
       </ul>
     
     <div style="padding:.5em 0 0 1em;">
-      <a href="//play.google.com/store/apps/details?id=com.rememberthemilk.MobileRTM">
+      <a href="http://play.google.com/store/apps/details?id=com.rememberthemilk.MobileRTM">
         <img alt="Android app on Google Play"
-         src="//developer.android.com/images/brand/en_generic_rgb_wo_45.png" />
+         src="{@docRoot}images/brand/en_generic_rgb_wo_45.png" />
       </a>
       
     </div>
@@ -64,9 +65,9 @@
   <div style="line-height:1.4em;">
     <p style="margin-top:0;margin-bottom:12px;">When the Android tablet guidelines
       came out in 2012, the team at Remember The Milk had already been thinking about
-      a redesign for their <a href="//play.google.com/store/apps/details?id=com.rememberthemilk.MobileRTM">feature-packed
+      a redesign for their <a href="http://play.google.com/store/apps/details?id=com.rememberthemilk.MobileRTM">feature-packed
       to-do list app</a>. Omar Kilani, Co-founder of Remember The Milk, explains how
-      <a href="//blog.rememberthemilk.com/2013/04/the-all-new-remember-the-milk-for-android-and-tablets-too/">updating</a>
+      <a href="http://blog.rememberthemilk.com/2013/04/the-all-new-remember-the-milk-for-android-and-tablets-too/">updating</a>
       their app to meet the tablet guidelines lead to an 83% jump in tablet installs: </p>
 
     <p>“We took this as an opportunity to think about how we were going to approach
@@ -138,7 +139,7 @@
     <div style="padding:.5em 0 0 1em;">
 <a href="http://play.google.com/store/apps/details?id=com.mint">
   <img alt="Android app on Google Play"
-       src="//developer.android.com/images/brand/en_generic_rgb_wo_45.png" />
+       src="{@docRoot}images/brand/en_generic_rgb_wo_45.png" />
 </a>
       
     </div>
@@ -228,7 +229,7 @@
     <div style="padding:.5em 0 0 1em;">
 <a href="http://play.google.com/store/apps/details?id=com.tinyco.village">
   <img alt="Android app on Google Play"
-       src="//developer.android.com/images/brand/en_generic_rgb_wo_45.png" />
+       src="{@docRoot}images/brand/en_generic_rgb_wo_45.png" />
 </a>
       
     </div>
@@ -318,7 +319,7 @@
     <div style="padding:.5em 0 0 1em;">
 <a href="http://play.google.com/store/apps/details?id=com.instapaper.android">
   <img alt="Android app on Google Play"
-       src="//developer.android.com/images/brand/en_generic_rgb_wo_45.png" />
+       src="{@docRoot}images/brand/en_generic_rgb_wo_45.png" />
 </a>
       
     </div>
diff --git a/docs/html/distribute/tools/disttools_toc.cs b/docs/html/distribute/tools/disttools_toc.cs
new file mode 100644
index 0000000..f4f39f0
--- /dev/null
+++ b/docs/html/distribute/tools/disttools_toc.cs
@@ -0,0 +1,46 @@
+<ul id="nav">
+
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/tools/launch-checklist.html">
+            <span class="en">Launch Checklist</span></a>
+    </div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/tools/localization-checklist.html">
+            <span class="en">Localization Checklist</span></a>
+    </div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/tools/promote/device-art.html">
+            <span class="en">Device Art Generator</span></a>
+    </div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/tools/promote/badges.html">
+            <span class="en">Google Play Badges</span></a>
+    </div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/tools/promote/linking.html">
+            <span class="en">Linking to Your Products</span></a>
+    </div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/tools/promote/brand.html">
+            <span class="en">Brand Guidelines</span></a>
+    </div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/tools/open-distribution.html">
+            <span class="en">Alternative Distribution</span></a>
+    </div>
+  </li>
+</ul>
+
+<script type="text/javascript">
+<!--
+    buildToggleLists();
+    changeNavLang(getLangPref());
+//-->
+</script>
+
diff --git a/docs/html/distribute/tools/index.jd b/docs/html/distribute/tools/index.jd
new file mode 100644
index 0000000..c8f0212
--- /dev/null
+++ b/docs/html/distribute/tools/index.jd
@@ -0,0 +1,57 @@
+page.title=Tools &amp; Reference
+section.landing=true
+nonavpage=true
+
+@jd:body
+
+<p>
+  Here you’ll find resources to help you publish your apps and games, acquire
+  users, and monetize your investment.
+</p>
+
+<div class="dynamic-grid">
+
+  <h3>Publishing and Launch</h3>
+  <div class="resource-widget resource-flow-layout landing col-16"
+    data-query="collection:distribute/tools/checklists"
+    data-cardSizes="9x6"
+    data-maxResults="2">
+  </div>
+
+<h3>Marketing Tools</h3>
+  <div class="resource-widget resource-flow-layout landing col-16"
+    data-query="collection:distribute/tools/promote"
+    data-cardSizes="6x6"
+    data-maxResults="3">
+  </div>
+
+  <h3>Developer Support</h3>
+  <div class="resource-widget resource-flow-layout landing col-16"
+    data-query="collection:distribute/tools/support"
+    data-cardSizes="6x6"
+    data-maxResults="3">
+  </div>
+
+  <h3>Developer News</h3>
+  <div class="resource-widget resource-flow-layout landing col-16"
+    data-query="collection:distribute/tools/news"
+    data-cardSizes="9x6"
+    data-maxResults="2">
+  </div>
+
+  <h3>More</h3>
+  <div class="resource-widget resource-flow-layout landing col-16"
+    data-query="collection:distribute/tools/more"
+    data-cardSizes="6x6"
+    data-maxResults="3">
+  </div>
+
+<!--  <h3>Related Resources</h3>
+  <div class="resource-widget resource-stack-layout col-16"
+    data-query="tag:developersupport"
+    data-sortOrder="-timestamp"
+    data-numStacks="3"
+    data-maxResults="6">
+  </div> -->
+
+</div>
diff --git a/docs/html/distribute/tools/launch-checklist.jd b/docs/html/distribute/tools/launch-checklist.jd
new file mode 100644
index 0000000..3b0dd55
--- /dev/null
+++ b/docs/html/distribute/tools/launch-checklist.jd
@@ -0,0 +1,1072 @@
+page.title=Launch Checklist
+page.metaDescription=Essential overview of the complete process of delivering your app to users. Read this checklist early in development to help you plan for a successful launch on Google Play.
+meta.tags="localizing, publishing, disttools"
+page.tags="launch, publishing, Google Play"
+page.image=/distribute/images/launch-checklist.jpg
+
+@jd:body
+
+<div id="qv-wrapper">
+  <div id="qv" style="width:280px">
+    <h2>Checklist</h2>
+    <ol>
+      <li><a href="#understand-publishing">1. Understand the Publishing Process</a></li>
+      <li><a href="#understand-policies">2. Understand Google Play Policies</a></li>
+      <li><a href="#test-quality">3. Test for Core App Quality</a></li>
+      <li><a href="#determine-rating">4. Determine Content Rating</a></li>
+      <li><a href="#determine-country">5. Determine Country Distribution</a></li>
+      <li><a href="#confirm-size">6. Confirm Overall Size</a></li>
+      <li><a href="#confirm-platform">7. Confirm Platform and Screen Ranges</a></li>
+      <li><a href="#decide-price">8. Decide Free or Priced</a></li>
+      <li><a href="#consider-billing">9. Use In-app Billing</a></li>
+      <li><a href="#set-prices">10. Set Prices for your Products</a></li>
+      <li><a href="#start-localization">11. Start Localization</a></li>
+      <li><a href="#prepare-graphics">12. Prepare Promotional Graphics, Screenshots, and Videos</a></li>
+      <li><a href="#build-upload">13. Build the Release-ready APK</a></li>
+      <li><a href="#plan-beta">14. Plan a Beta Release</a></li>
+      <li><a href="#complete-details">15. Complete the Store Listing</a></li>
+      <li><a href="#use-badges">16. Use Google Play Badges and Links</a></li>
+      <li><a href="#final-checks">17. Final Checks and Publishing</a></li>
+      <li><a href="#support-users">18. Support Users after Launch  </a></li>
+    </ol>
+  </div>
+</div>
+
+<div class="top-right-float" style="width:194px"><img
+src="{@docRoot}distribute/images/launch-checklist.jpg"></div>
+
+<p>
+  Before you publish your apps on Google Play and distribute them to users, you
+  need to get the apps ready, test them, and prepare your promotional
+  materials.
+</p>
+
+<p>
+  This page helps you understand the publishing process and get ready for a
+  successful product launch on Google Play. It summarizes some of the tasks
+  you'll need to complete before publishing your app on Google Play, such as
+  creating a signed, release-ready application package (APK), understanding the
+  requirements of the app, and creating the product page and graphic assets for
+  each of your apps.
+</p>
+
+<p>
+  The preparation and publishing tasks are numbered to give you a rough idea of
+  sequence. However, you can handle the tasks in any sequence that works for
+  you or you can skip steps as appropriate.
+</p>
+
+<p>
+  As you move toward publishing, a variety of support resources are available
+  to you. Relevant links are provided in each step.
+</p>
+
+<div class="headerLine">
+  <h1 id="understand-publishing">
+    1. Understand the Publishing Process
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  Before you begin the steps in this checklist, you should take a moment to
+  read and understand the overall publishing workflow and become familiar with
+  how the process works. In particular, you or your development team will need
+  to prepare your apps for release using a process common to all Android apps.
+  The <a href="{@docRoot}tools/publishing/publishing_overview.html">Publishing
+  workflow documents</a> provide the details on how publishing works and how to
+  get an APK ready for release.
+</p>
+
+<p>
+  Once you are familiar with publishing in general, continue reading to
+  understand the issues that you should consider when publishing apps on Google
+  Play.
+</p>
+
+<h3>
+  Related resources
+</h3>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/toolsreference/launchchecklist/understanding"
+data-sortorder="-timestamp" data-cardsizes="9x3,9x3,6x3,9x3,9x3,9x3"
+data-maxresults="6">
+</div>
+
+<div class="headerLine clearfloat">
+  <h1 id="understand-policies">
+    2. Understand Google Play Policies and Agreements
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  Make sure that you understand and follow the Google Play program policies
+  that you accepted when registering. Google Play actively enforces the
+  policies and any violations can lead to suspension of your apps or, for
+  repeated violations, termination of your developer account.
+</p>
+
+<h3>
+  Related resources
+</h3>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/toolsreference/launchchecklist/policies" data-sortorder=
+"-timestamp" data-cardsizes="6x3" data-maxresults="6">
+</div>
+
+<div class="headerLine clearfloat">
+  <h1 id="test-quality">
+    3. Test for Quality
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  Before you publish apps on Google Play, it's important to make sure that they
+  meet the basic quality expectations for all Android apps, on all of the
+  devices that you are targeting. You can check your app's quality by setting
+  up a test environment and testing the app against a short set of
+  <strong>quality criteria that applies to all apps</strong>. For complete
+  information, see the <a href=
+  "{@docRoot}distribute/essentials/quality/core.html">Core App Quality</a>
+  guidelines.
+</p>
+
+<p>
+  If your app is targeting tablet devices, make sure that it delivers a rich,
+  compelling experience to your tablet customers. See the <a href=
+  "{@docRoot}distribute/essentials/quality/tablets.html">Tablet App Quality</a>
+  guidelines for recommendations on ways to optimize your app for tablets.
+</p>
+
+<p>
+  If you plan to make your apps available to Google Play for Education, then
+  you need to make sure they are suitable for a K-12 classroom and offer
+  outstanding educational value. See the <a href=
+  "{@docRoot}distribute/essentials/gpfe-guidelines.html">Education
+  Guidelines</a> for information on the characteristics your education apps
+  should exhibit.
+</p>
+
+<h3>
+  Related resources
+</h3>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/toolsreference/launchchecklist/quality" data-sortorder=
+"-timestamp" data-cardsizes="6x3,6x3,6x3,9x3,9x3,9x3" data-maxresults="6">
+</div>
+
+<div class="headerLine clearfloat">
+  <h1 id="determine-rating">
+    4. Determine your App’s Content Rating
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  Google Play requires you to set a content rating for your app, which informs
+  Google Play users of its maturity level. Before you publish, you should
+  confirm what rating level you want to use. The available content rating
+  levels are:
+</p>
+
+<ul>
+  <li>
+    <p>
+      Everyone
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Low maturity
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Medium maturity
+    </p>
+  </li>
+
+  <li>
+    <p>
+      High maturity
+    </p>
+  </li>
+</ul>
+
+<p>
+  On their Android devices, Android users can set the desired maturity level
+  for browsing. Google Play then filters apps based on the setting, so the
+  content rating you select can affect the app's distribution to users. You can
+  assign (or change) the content rating for your apps in the Developer Console,
+  no changes are required in your app binary.
+</p>
+
+<h3>
+  Related resources
+</h3>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/toolsreference/launchchecklist/rating" data-sortorder=
+"-timestamp" data-cardsizes="9x3,6x3,6x3,9x3,9x3,9x3" data-maxresults="6">
+</div>
+
+<div class="headerLine clearfloat">
+  <h1 id="determine-country">
+    5. Determine Country Distribution
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  Google Play lets you control what countries and territories your apps are
+  distributed to. For the widest reach and the largest potential customer base,
+  you’d normally want to distribute to all available countries and territories.
+  However, because of business needs, app requirements, or launch dependencies,
+  you might want to exclude one or more countries from your distribution.
+</p>
+
+<p>
+  It's important to determine the exact country distribution early, because it
+  can affect:
+</p>
+
+<ul>
+  <li>
+    <p>
+      The need for localized resources in the app.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      The need for a localized app description in the Developer Console.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Legal requirements for the app that may be specific to certain countries.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Time zone support, local pricing, and so on.
+    </p>
+  </li>
+</ul>
+
+<p>
+  With your target countries in mind, you should assess your localization
+  needs, both in your apps and in their Google Play listings details, and start
+  the work of localization well in advance of your target launch date.
+</p>
+
+<p>
+  See <a href=
+  "{@docRoot}distribute/tools/localization-checklist.html">Localization
+  Checklist</a> for key steps and considerations in the localization process.
+</p>
+
+<h3>
+  Related resources
+</h3>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/toolsreference/launchchecklist/country" data-sortorder=
+"-timestamp" data-cardsizes="9x3,9x3,6x3,9x3,9x3,9x3" data-maxresults="6">
+</div>
+
+<div class="headerLine clearfloat">
+  <h1 id="confirm-size">
+    6. Confirm the App's Overall Size
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  The overall size of your app can affect its design and how you publish it on
+  Google Play. Currently, the maximum size for an APK published on Google Play
+  is <strong>50 MB</strong>. If your app exceeds that size, or if you want to
+  offer a secondary download, you can use <a href=
+  "{@docRoot}google/play/expansion-files.html">APK Expansion Files</a>, which
+  Google Play will host for free on its server infrastructure and automatically
+  handle the download to devices.
+</p>
+
+<ul>
+  <li>
+    <p>
+      The maximum size for an APK published on Google Play is 50 MB.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      You can use up to two (2) APK Expansion Files, each up to 2GB in size,
+      for each APK.
+    </p>
+  </li>
+</ul>
+
+<p>
+  Using APK Expansion files is a convenient, cost-effective method of
+  distributing large apps. However, the use of APK Expansion Files requires
+  some changes in your app binary, so you will need to make those changes
+  before creating your release-ready APK.
+</p>
+
+<p>
+  To minimize the size of your app binary, make sure that you run the <a href=
+  "{@docRoot}tools/help/proguard.html">Proguard</a> tool or similar obfuscator
+  on your code when building your release-ready APK.
+</p>
+
+<h3>
+  Related resources
+</h3>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/toolsreference/launchchecklist/size" data-sortorder=
+"-timestamp" data-cardsizes="9x3,9x3,6x3,9x3,9x3,9x3" data-maxresults="6">
+</div>
+
+<div class="headerLine clearfloat">
+  <h1 id="confirm-platform">
+    7. Confirm the App's Platform and Screen Compatibility Ranges
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  Before publishing, it's important to make sure that your apps are designed to
+  run properly on the Android platform versions and device screen sizes that
+  you want to target.
+</p>
+
+<p>
+  From an app-compatibility perspective, Android platform versions are defined
+  by <a href=
+  "{@docRoot}guide/topics/manifest/uses-sdk-element.html#ApiLevels">API
+  level</a>. You should confirm the minimum version that your app is compatible
+  with <a href=
+  "{@docRoot}guide/topics/manifest/uses-sdk-element.html">&lt;minSdkVersion&gt;</a>,
+  as that will affect its distribution to Android devices once it is published.
+</p>
+
+<p>
+  For screen sizes, you should confirm that the app runs properly and looks
+  good on the range of screen sizes and pixel densities that you want to
+  support. You should follow the advice provided in <a href=
+  "{@docRoot}guide/practices/screens_support.html">Supporting Multiple
+  Screens</a> to provide scalable support for multiple screen sizes. However,
+  if you have been unable to do so, declare the minimum screen-size supported
+  by your apps using <a href=
+  "{@docRoot}guide/topics/manifest/supports-screens-element.html">&lt;supports-screens&gt;</a>.
+  Google Play will then restrict the availability of your apps accordingly,
+  making them available to devices with the declared screen size or large.
+</p>
+
+<p>
+  To get a better understanding of the current device penetration of Android
+  platform versions and screen sizes across all Android devices, see the
+  <a href="{@docRoot}about/dashboards/index.html">Device Dashboard</a> charts.
+</p>
+
+<h3>
+  Related resources
+</h3>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/toolsreference/launchchecklist/platform" data-sortorder=
+"-timestamp" data-cardsizes="6x3,6x3,6x3" data-maxresults="6">
+</div>
+
+<div class="headerLine clearfloat">
+  <h1 id="decide-price">
+    8. Decide Whether your App will be Free or Priced
+  </h1>
+
+  <hr>
+</div>
+
+<div class="figure">
+  <img src="{@docRoot}images/gp-launch-checklist-1.png">
+</div>
+
+<p>
+  On Google Play, you can publish apps as free to download or priced. Free apps
+  can be downloaded by any Android user in Google Play. Paid apps can be
+  downloaded only by users who are in a country that supports paid downloads
+  and have registered a form of payment in Google Play, such as a credit card
+  or Direct Carrier Billing.
+</p>
+
+<p>
+  Deciding whether you apps will be free or paid is important because, on
+  Google Play, <strong>free apps must remain free</strong>.
+</p>
+
+<ul>
+  <li>
+    <p>
+      Once you publish an app as a free app, you cannot change it to being a
+      priced app. However, you can still sell <a href=
+      "{@docRoot}google/play/billing/billing_overview.html#products">in-app
+      products</a> and <a href=
+      "{@docRoot}google/play/billing/billing_subscriptions.html">subscriptions</a>
+      through Google Play's <a href=
+      "{@docRoot}google/play/billing/index.html">In-app Billing</a> service.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      If you publish your app as a priced app, you <em>can</em> change it at
+      any time to be a free app (<strong>but cannot then change it back to
+      priced</strong>). You can also sell in-app products and subscriptions.
+    </p>
+  </li>
+</ul>
+
+<p>
+  If your app is be priced, or if you'll be selling in-app products, you need
+  <a href=
+  "https://developers.google.com/wallet/digital/training/getting-started/merchant-setup">
+  set up a Google Wallet Merchant Account</a> before you can publish.
+</p>
+
+<h3>
+  Related resources
+</h3>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/toolsreference/launchchecklist/price" data-sortorder=
+"-timestamp" data-cardsizes="9x3,9x3,6x3,9x3,9x3,9x3" data-maxresults="6">
+</div>
+
+<div class="headerLine clearfloat">
+  <h1 id="consider-billing">
+    9. Consider using In-app Billing
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  Google Play <a href="{@docRoot}google/play/billing/index.html">In-app
+  Billing</a> lets you sell digital content in your applications. You can use
+  the service to sell a wide range of content, including downloadable content
+  such as media files or photos, and virtual content such as game levels or
+  potions. In-app Billing service lets you sell one-time purchases and
+  subscriptions from inside your app. This can help you to monetize the app
+  over its installed lifetime.
+</p>
+
+<p>
+  If your are looking for more ways to monetize your app and build engagement,
+  you should consider In-app Billing or Instant Buy. These services have become
+  very popular with both users and developers. To use In-app Billing or Instant
+  Buy, you need to make changes to your app binary, so you will need to
+  complete and test your implementation before creating your release-ready APK.
+</p>
+
+<h3>
+  Related resources
+</h3>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/toolsreference/launchchecklist/purchasemethod"
+data-sortorder="-timestamp" data-cardsizes="9x3,9x3,6x3,9x3,9x3,9x3"
+data-maxresults="6">
+</div>
+
+<div class="headerLine clearfloat">
+  <h1 id="set-prices">
+    10. Set Prices for your Products
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  If your apps is priced or you’ll sell in-app or physical products, Google
+  Play lets you set prices for your products in a variety of currencies, for
+  users in markets around the world. You can set prices individually in
+  different currencies, so you have the flexibility to adjust your price
+  according to market conditions and exchange rates.
+</p>
+
+<p>
+  Before you publish, consider how you’ll price your products and what your
+  prices will be in various currencies. Later, you can set prices in all
+  available currencies through the Developer Console.
+</p>
+
+<h3>
+  Related resources
+</h3>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/toolsreference/launchchecklist/setprice" data-sortorder=
+"-timestamp" data-cardsizes="9x3,9x3,9x3,9x3,9x3,9x3" data-maxresults="6">
+</div>
+
+<div class="headerLine clearfloat">
+  <h1 id="start-localization">
+    11. Start Localization
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  With your country targeting in mind, it's a good idea to assess your
+  localization needs, ensure your apps are internationalized, and start the
+  work of localizing well in advance of your target launch date.
+</p>
+
+<p>
+  In addition to your application design, there are at least three aspects of
+  localization to consider:
+</p>
+
+<ul>
+  <li>
+    <p>
+      Localizing the strings, images, and other resources in your apps.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Localizing your apps’ store listing details on Google Play.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Localizing the apps’ graphic assets, screenshots, and videos that
+      accompany your store listing.
+    </p>
+  </li>
+</ul>
+
+<p>
+  See <a href=
+  "{@docRoot}distribute/tools/localization-checklist.html">Localization
+  Checklist</a> for key steps and considerations in the localization process.
+</p>
+
+<p>
+  To localize your store listing, first create and finalize your app title,
+  description, and promotional text. Collect and send all of these for
+  localization. You can optionally translate the "Recent Changes" text for app
+  updates as well. Later you can add your localized listing details in the
+  Developer Console, or you can choose to let Google Play auto-translate your
+  listing details into the languages you support.
+</p>
+
+<p>
+  A key part of making your app listing attractive to a global customer base is
+  creating localized versions of your promotional graphics, screenshots and
+  videos. For example, your app's feature graphic might include text that
+  should be translated, for maximum effectiveness. You can create different
+  versions of your promotional graphics for each language and upload them to
+  the Developer Console. If you offer a promotional video, you can create
+  localized versions of it and then add a link to the correct localized video
+  for each language you support.
+</p>
+
+<p>
+  When your translations are complete, move them into your app resources as
+  needed and test that they are loaded properly. Save your app's translated
+  listing details for later, when you upload assets and configure the store
+  listing.
+</p>
+
+<h3>
+  Related resources
+</h3>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/toolsreference/launchchecklist/localization"
+data-sortorder="-timestamp" data-cardsizes="9x3,9x3,6x3,9x3,9x3,9x3"
+data-maxresults="6">
+</div>
+
+<div class="headerLine clearfloat">
+  <h1 id="prepare-graphics">
+    12. Prepare Promotional Graphics, Screenshots, and Videos
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  When you publish on Google Play, you can supply a variety of high-quality
+  graphic assets to showcase your app or brand. After you publish, these appear
+  on your store listing page, search results, and elsewhere. These graphic
+  assets are key parts of a successful store listing page that attracts and
+  engages users, so you should consider having a professional produce them for
+  you. Screenshots and videos are also very important, because they show how
+  your apps look, how they’re used or played, and what makes them different.
+</p>
+
+<p>
+  All of your graphic assets should be designed so that they are easy to see
+  and highlight your apps or brand in a colorful, interesting way. The assets
+  should reference the same logo and icon as users will find in the All Apps
+  launcher once they have downloaded the app. Your graphic assets should also
+  fit in well with the graphic assets of all the apps you publish, which will
+  be also be displayed to users on your store listing page.
+</p>
+
+<p>
+  To help you market your apps more effectively to a global audience, Google
+  Play lets you create localized versions of your promotional graphics,
+  screenshots, and videos and upload them to the Developer Console. When a user
+  visits your app's store listing, Google Play displays the promotional
+  graphic, screenshots, and video that you've provided for the user's language.
+</p>
+
+<p>
+  To localize your promotional graphics, you can translate any embedded text,
+  use different imagery or presentation, or change your marketing approach to
+  best address the needs of users in specific languages. For example, if your
+  feature or promotional graphic includes an embedded product name or tag line,
+  you can translate that text and add it to a localized version of the
+  promotional graphic.
+</p>
+
+<p>
+  Because your localized graphic assets and videos are so important, you should
+  get started on creating and localizing them well in advance of your target
+  publishing date.
+</p>
+
+<h3>
+  Related resources
+</h3>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/toolsreference/launchchecklist/graphics" data-sortorder=
+"-timestamp" data-cardsizes="9x3,9x3,6x3,9x3,9x3,9x3" data-maxresults="6">
+</div>
+
+<div class="headerLine clearfloat">
+  <h1 id="build-upload">
+    13. Build and Upload the Release-ready APK
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  When you are satisfied that your apps meet your UI, compatibility, and
+  quality requirements, you can build the release-ready versions of the apps.
+  You upload the release-ready APKs to your Developer Console and distribute to
+  users.
+</p>
+
+<p>
+  The process for preparing a release-ready APK is the same for all apps,
+  regardless of how they are distributed. Generally the process includes basic
+  code cleanup and optimization, building and signing with your release key,
+  and final testing.
+</p>
+
+<p>
+  For complete details on how to create a release-ready version of your app,
+  read <a href="{@docRoot}tools/publishing/preparing.html">Preparing for
+  Release</a>.
+</p>
+
+<p>
+  Once you have the release-ready APKs in hand, you can upload them to the
+  Developer Console. If necessary, you can replace an APK with a more recent
+  version before publishing.
+</p>
+<!--<h3>Related resources</h3>
+
+<div class="resource-widget resource-flow-layout col-13"
+  data-query="collection:distribute/toolsreference/launchchecklist/build"
+  data-sortOrder="-timestamp"
+  data-cardSizes="9x3,9x3,6x3,9x3,9x3,9x3"
+  data-maxResults="6"></div>-->
+
+<div class="headerLine clearfloat">
+  <h1 id="plan-beta">
+    14. Plan a Beta Release
+  </h1>
+
+  <hr>
+</div>
+
+<div class="sidebox-wrapper" style="float:right;">
+  <div class="sidebox">
+    <h2>
+      Easy beta testing
+    </h2>
+
+    <p>
+      Google Play lets you set up groups of alpha and beta testers, anywhere
+      around the world. Check out this powerful feature next time you sign in
+      to the Developer Console.
+    </p>
+  </div>
+</div>
+
+<p>
+  Before launching your apps, it's always valuable to get real-world feedback
+  from users &mdash; even more so when you are launching new apps. It's highly
+  recommended that you distribute a pre-release version of your app to users
+  across your key markets and provide an easy means for them to provide
+  feedback and report bugs.
+</p>
+
+<p>
+  Google Play can help you set up a beta program for your app. After you sign
+  in to your Developer Console and have upload your APKs, you can set up groups
+  of users for alpha and beta testing the apps. You can start with a small
+  group of alpha testers, then move to a larger group of beta testers. Once
+  users are added, they access your app's store listing and install the app.
+  <strong>Users on alpha or beta versions cannot leave reviews or
+  ratings</strong>, so there is <strong>no risk to your rating</strong> on
+  Google Play. You need to arrange a mechanism for any testing feedback to be
+  delivered - such as a Google Forum or Google+.
+</p>
+
+<p>
+  The feedback you receive will help you adjust your UI, translations, and
+  store listing to ensure a great experience for users.
+</p>
+<!-- Related resources
+
+<table>
+  <tr>
+    <td>Beta-testing and Staged Rollouts
+See how you can facilitate testing with Google Play.</td>
+  </tr>
+</table> -->
+
+<div class="headerLine">
+  <h1 id="complete-details">
+    15. Complete the Apps’ Store Listing
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  On Google Play, your apps’ product information is shown to users on their
+  store listing pages, the pages that users visit to learn more about your apps
+  and the pages from which they will decide to purchase or download your apps,
+  on their Android devices or on the web.
+</p>
+
+<p>
+  Google Play gives you a variety of ways to promote your apps and engage with
+  users on your store listing pages, from colorful graphics, screenshots, and
+  videos to localized descriptions, release details, and links to your other
+  apps. As you prepare to publish your apps, make sure that you take advantage
+  of all that your product detail pages can offer, making your apps as
+  compelling as possible to users.
+</p>
+
+<p>
+  You should begin planning your product pages in advance of your target launch
+  date, arranging for localized description, high-quality graphic assets,
+  screenshots and video, and so on.
+</p>
+
+<p>
+  As you get near your target publishing date, you should become familiar with
+  all the fields, options, and assets associated with the store listing
+  configuration page in the Developer Console. As you collect the information
+  and assets for the page, make sure that you can enter or upload it to the
+  Developer Console, until the page is complete and ready for publishing.
+</p>
+
+<p>
+  After you've set your apps’ geographic targeting in the Developer Console,
+  remember to add your localized store listing, promotional graphics, and so
+  on, for all of the languages that you support.
+</p>
+
+<p>
+  If your app is targeting tablet devices, make sure to include at least one
+  screenshot of the app running on a tablet, and highlight your apps’ support
+  for tablets in the app description, release notes, promotional campaigns, and
+  elsewhere.
+</p>
+
+<h3>
+  Related resources
+</h3>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/toolsreference/launchchecklist/productdetails"
+data-sortorder="-timestamp" data-cardsizes="9x3,9x3,6x3,9x3,9x3,9x3"
+data-maxresults="6">
+</div>
+
+<div class="headerLine clearfloat">
+  <h1 id="use-badges">
+    16. Use Google Play Badges and Links in your Promotional Campaigns
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  Google Play badges give you an officially branded way of promoting your apps
+  to Android users. Use the <a href=
+  "{@docRoot}distribute/tools/promote/badges.html">Google Play Badge
+  generator</a> to quickly create badges to link users to your products from
+  web pages, ads, reviews, and more. You can also use special <a href=
+  "{@docRoot}distribute/tools/promote/linking.html">link formats</a> to link
+  directly to your store listing page, to a list of your products, or to search
+  results.
+</p>
+
+<p>
+  To help your apps get traction after launch, it's strongly recommended that
+  you support launch with a promotional campaign that announces your product
+  through many channels as possible, in as many countries as possible. For
+  example, you can promote a launch using ad placements, social network or blog
+  posts, video and other media, interviews and reviews, or any other channels
+  available.
+</p>
+
+<h3>
+  Related resources
+</h3>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/toolsreference/launchchecklist/badges" data-sortorder=
+"-timestamp" data-cardsizes="9x3,9x3,6x3,9x3,9x3,9x3" data-maxresults="6">
+</div>
+
+<div class="headerLine clearfloat">
+  <h1 id="final-checks">
+    17. Final Checks and Publishing
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  When you think you’re ready to publish, sign in to the Developer Console and
+  take a few moments for a few final checks.
+</p>
+
+<p>
+  Make sure that:
+</p>
+
+<ul>
+  <li>
+    <p>
+      Your developer profile has the correct information and is linked to the
+      proper Google Wallet merchant account (if you’re selling products).
+    </p>
+  </li>
+
+  <li>
+    <p>
+      You have the right version of the apps uploaded.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      All parts of your store listing are ready, including all graphic assets,
+      screenshots, video, localized descriptions, and so on.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      You have set your app's pricing to free or priced.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      You have set country (and carrier) targeting and priced your products (if
+      appropriate) in buyer currencies
+    </p>
+  </li>
+
+  <li>
+    <p>
+      "Compatible devices" shows that your apps are reaching the devices that
+      you’re targeting. If not, you should check with your development team on
+      the apps’ requirements and filtering rules.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      You’ve provided the correct link to your website and the correct support
+      email address.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Your apps don’t violate content policy guidelines.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      You’ve acknowledged that your apps meets the guidelines for Android
+      content on Google Play and also US export laws.
+    </p>
+  </li>
+</ul>
+
+<p>
+  Your apps are now ready to publish!
+</p>
+
+<p>
+  If you’re releasing an update, make sure to read the <a href=
+  "http://support.google.com/googleplay/android-developer/bin/answer.py?hl=en&amp;answer=113476&amp;topic=2365760&amp;ctx=topic">
+  requirements for publishing updates</a>.
+</p>
+
+<p>
+  When you’re ready, click the <strong>Publish</strong> button in the Developer
+  Console. Within a few hours, your apps will become available to users and
+  your product page will appear in Google Play for browsing, searching, or
+  linking from your promotional campaigns.
+</p>
+
+<h3>
+  Related resources
+</h3>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/toolsreference/launchchecklist/finalchecks"
+data-sortorder="-timestamp" data-cardsizes="6x3,6x3,6x3,9x3,9x3,9x3"
+data-maxresults="6">
+</div>
+
+<div class="headerLine clearfloat">
+  <h1 id="support-users">
+    18. Support Users after Launch
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  After you publish apps or app updates, it's crucial for you to support your
+  customers. Prompt and courteous support can provide a better experience for
+  users that results in better ratings and more positive reviews for your
+  products. Users are likely to be more engaged with your app and recommend it
+  if you’re responsive to their needs and feedback. This is especially true
+  after publishing if you’re using a coordinated promotional campaign.
+</p>
+
+<p>
+  There are a number of ways that you can keep in touch with users and offer
+  them support. The most fundamental is to provide your <em>support email
+  address</em> on your store listing pages. Beyond that, you can provide
+  support in any way you choose, such as a forum, mailing list, or a Google+
+  page. The Google Play team provides user support for downloading, installing.
+  and payments issues, but issues that fall outside of these topics will be in
+  your domain. Examples of issues you can support include: feature requests,
+  questions about using the apps, and questions about compatibility settings.
+</p>
+
+<p>
+  After publishing, plan to:
+</p>
+
+<ul>
+  <li>
+    <p>
+      Check your ratings and reviews frequently on your apps’ store listing
+      pages. Watch for recurring themes that could signal bugs or other issues.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Be mindful of new Android platform version launches, as compatibility
+      settings for your apps might need to be updated.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Put a link to your support resources on your website and set up any other
+      support such as forums.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Provide an appropriate support email address on your store listing pages
+      and respond to users when they take the time to email you.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Beyond the automatic refund window offered by Google Play, be generous
+      with your own refund policy, as satisfied users will be more likely to
+      purchase in the future.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Acknowledge and fix issues in your apps. It helps to be transparent and
+      list known issues on your store listing pages proactively.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Publish updates as frequently as you’re able, without sacrificing quality
+      or annoying users with too-frequent updates.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      With each update, make sure to provide a summary of what's changed. You
+      can enter this information in the Developer Console. Users will read it
+      and appreciate that you are serious about improving the quality of your
+      apps.
+    </p>
+  </li>
+</ul>
+</ul>
+
+<h3>Related resources</h3>
+
+<div class="resource-widget resource-flow-layout col-13"
+  data-query="collection:distribute/toolsreference/launchchecklist/afterlaunch"
+  data-sortOrder="-timestamp"
+  data-cardSizes="9x3,9x3,9x3,9x3,9x3,9x3"
+  data-maxResults="6"></div>
diff --git a/docs/html/distribute/tools/localization-checklist.jd b/docs/html/distribute/tools/localization-checklist.jd
new file mode 100644
index 0000000..7a638ed
--- /dev/null
+++ b/docs/html/distribute/tools/localization-checklist.jd
@@ -0,0 +1,978 @@
+page.title=Localization Checklist
+page.metaDescription=Take advantage of the worldwide audience offered by Android and Google Play. Read this checklist to get an overview of how to deliver your product to markets around the world.
+meta.tags="localizing, publishing, disttools"
+page.tags="local, l10n, translation, language"
+page.image=/distribute/images/localization-checklist.jpg
+
+@jd:body
+
+<div id="qv-wrapper">
+  <div id="qv" style="width:280px">
+    <h2>Checklist</h2>
+    <ol>
+      <li><a href="#identify-languages">1. Identify target languages and locales</a></li>
+      <li><a href="#design">2. Design for localization</a></li>
+      <li><a href="#manage-strings">3. Manage strings for localization</a></li>
+      <li><a href="#translate-strings">4. Translate UI strings and other resources</a></li>
+      <li><a href="#test">5. Test your localized app</a></li>
+      <li><a href="#prepare-launch">6. Prepare for international launch</a></li>
+      <li><a href="#support-users">7. Support international users after launch</a></li>
+    </ol>
+  </div>
+</div>
+
+<div class="top-right-float" style="width:194px">
+  <img src="{@docRoot}distribute/images/localization-checklist.jpg">
+</div>
+
+<p>
+  Android and Google Play offer you a worldwide audience for your apps, with an
+  addressable user base that's growing very rapidly in countries such as Japan,
+  Korea, India, Brazil, and Russia. We strongly encourage you to localize as it
+  can maximize your apps’ distribution potential resulting in ratings from
+  users around the world.
+</p>
+
+<p>
+  Localization involves a variety of tasks throughout your app development
+  cycle, and advance planning is essential. This document helps you identify
+  key aspects of localization to get your app ready for a successful worldwide
+  launch on Google Play.
+</p>
+
+<div class="headerLine">
+  <h1 id="identify-languages">
+    1. Identify target languages and locales
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  A basic but important step in preparing for localization is identifying the
+  countries where you’ll distribute your apps and the languages spoken there.
+  Localizing your apps is particularly important in countries where there is a
+  large market opportunity and English or another international language is not
+  widely used.
+</p>
+
+<p>
+  For international users, you can manage your apps in three main dimensions:
+  country, locale, and language. Of those, language is the key consideration
+  for localization (locale can also significant because of differences in
+  formats for dates, times, currencies, and similar information). Users control
+  both the language and locale used on their Android devices and in turn those
+  affect how your app is displayed.
+</p>
+
+<p>
+  Typically, you would decide which countries to target first, based on overall
+  market size and opportunity, app category, competitive landscape, local
+  pricing and financial factors, and so on. Then, based on your country
+  targeting, you would determine the languages you need to support in your
+  apps.
+</p>
+
+<p>
+  You may then decide to localize into some or all languages of the targeted
+  country. It might make sense to start with a major regional language and add
+  more languages as user base grows.
+</p>
+
+<p>
+  Once you have identified your target languages, you can focus your
+  development, translation, testing, and marketing efforts to these markets.
+</p>
+
+<h3 id="related-resources">
+  Related Resources
+</h3>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/toolsreference/localizationchecklist/identifylocales"
+data-sortorder="-timestamp" data-cardsizes="9x3," data-maxresults="6">
+</div>
+
+<div class="headerLine clearfloat">
+  <h1 id="design">
+    2. Design for localization
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  After you've determined your target languages for localization, assess what
+  you'll need to do to support them in your apps and plan the work early.
+  Consider the vocabulary expansion, script requirements, character spacing and
+  wrapping constraints, left-to-right and right-to-left support, and other
+  potential factors in each language.
+</p>
+
+<h4>
+  <strong>Design a single set of flexible layouts</strong>
+</h4>
+
+<p>
+  As you create your layouts, make sure that any UI elements that hold text are
+  designed generously. It’s good to allow more space than necessary for your
+  language (up to 30% more is normal) to accommodate other languages.
+</p>
+
+<p>
+  Also, elements should be able to expand horizontally or vertically to
+  accommodate variations in the width and height of UI strings or input text.
+  Your text strings shouldn’t overlap borders or the screen edge in any of your
+  target languages.
+</p>
+
+<p>
+  If you design your UI carefully, you can typically use a single set of
+  layouts for all of the languages you support. See <a href=
+  "{@docRoot}training/basics/fragments/fragment-ui.html">Building a Flexible
+  UI</a> for more information.
+</p>
+
+<h4>
+  <strong>Use alternative layouts where needed</strong>
+</h4>
+
+<p>
+  In cases where your UI can't accommodate text in one of your target
+  languages, you can create an <a href=
+  "{@docRoot}guide/topics/resources/providing-resources.html#AlternativeResources">
+  alternative layout</a> for that language only. Android makes it easy to
+  declare sets of layouts and other resources to load for specific languages,
+  locales, screen sizes, and so on, simply by tagging them with the appropriate
+  resource qualifiers. While the flexibility of alternative layouts exists it
+  can also make your apps harder to maintain over time. In general, using a
+  single, more flexible layout is preferred.
+</p>
+
+<h4>
+  <strong>Support RTL layouts and text</strong>
+</h4>
+
+<p>
+  If you’re distributing to countries where right-to-left (RTL) scripts are
+  used, you should consider implementing support for RTL layouts and text
+  display and editing, to the extent possible.
+</p>
+
+<p>
+  Android 4.1 introduced limited support for bidirectional text, allowing apps
+  to display and edit text in both left-to-right (LTR) and right-to-left (RTL)
+  scripts. Android 4.2 added <a href=
+  "http://android-developers.blogspot.fr/2013/03/native-rtl-support-in-android-42.html">
+  full native support for RTL layouts</a>, including layout mirroring, so that
+  you can deliver the same great app experiences to all of your users.
+</p>
+
+<p>
+  At a minimum, for Android 4.2 users, it's simple to add basic RTL layout
+  mirroring, which goes a long way toward meeting the needs of RTL users.
+</p>
+
+<h4>
+  <strong>Use system-provided formats for dates, times, numbers, and
+  currencies</strong>
+</h4>
+
+<p>
+  Where your apps specify dates, times, numbers, currencies, and other entities
+  that can vary by locale, make sure to use the system-provided formats, rather
+  than app-specific formats. Keep in mind that not every locale uses the same
+  thousands separator, decimal separator, or percent sign.
+</p>
+
+<p>
+  Android provides a variety of utilities for formatting and converting
+  patterns across locales, such as <a href=
+  "{@docRoot}reference/android/text/format/DateUtils.html">DateUtils</a> and
+  <a href="{@docRoot}reference/java/text/DateFormat.html">DateFormat</a> for
+  dates; <a href=
+  "{@docRoot}reference/java/lang/String.html#format(java.lang.String,%20java.lang.Object...)">
+  String.format()</a> or <a href=
+  "{@docRoot}reference/java/text/DecimalFormat.html">DecimalFormat</a> for
+  numbers and currency; <a href=
+  "{@docRoot}reference/android/telephony/PhoneNumberUtils.html">PhoneNumberUtils</a>
+  for phone numbers; and others.
+</p>
+
+<p>
+  Hardcoding your formats based on assumptions about the user's locale can
+  result in problems when the user changes to another locale. Using
+  system-provided formats and utilities is strongly encouraged.
+</p>
+
+<h4>
+  <strong>Include a full set of default resources</strong>
+</h4>
+
+<p>
+  Make sure that your apps can run properly regardless of language or locale by
+  providing a complete set of default resources. The app's default resources
+  are those that are <em>not marked</em> with any language or locale
+  qualifiers, for example those stored in res/drawable/ and res/values/. If
+  your apps attempt to load a resource that isn't available in the current
+  language or in the default set, they will crash.
+</p>
+
+<p>
+  Whatever the default language you’re using in your apps, make sure that you
+  store the associated layouts, drawables, and strings in default resource
+  directories, without language or locale qualifiers.
+</p>
+
+<h3>
+  Related resources
+</h3>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/tools/loc/designforloc" data-sortorder="-timestamp"
+data-cardsizes="9x3" data-maxresults="6">
+</div>
+
+<div class="headerLine clearfloat">
+  <h1 id="manage-strings">
+    3. Manage strings for localization
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  It's important to manage your apps’ UI strings properly, so that you deliver
+  a great experience for users and make localization straightforward.
+</p>
+
+<h4>
+  <strong>Move all strings into strings.xml</strong>
+</h4>
+
+<p>
+  As you build your apps, remember not to hard code any string. Instead declare
+  <em>all</em> of your strings as resources in a default strings.xml file which
+  makes it easy to update and localize. Strings in strings.xml file can be
+  extracted, translated and integrated back into your app (with appropriate
+  qualifiers) without any changes to compiled code.
+</p>
+
+<p>
+  If you generate images with text, put those strings in strings.xml as well,
+  and regenerate the images after translation.
+</p>
+
+<h4>
+  <strong>Follow Android guidelines for UI strings</strong>
+</h4>
+
+<p>
+  As you design and develop your UIs, make sure that you pay close attention to
+  <em>how</em> you talk to your user. In general, use a <a href=
+  "{@docRoot}design/style/writing.html">succinct and compressed style</a> that
+  is friendly but brief, and use a consistent style throughout your UIs.
+</p>
+
+<p>
+  Make sure that you read and follow the Android Design recommendations for
+  <a href="{@docRoot}design/style/writing.html">writing style and word
+  choice</a>. Doing so will make your apps appear more polished to the user and
+  will help users understand your UI more quickly.
+</p>
+
+<p>
+  Also, always use Android standard terminology wherever possible&mdash;such as
+  for UI elements such as "Action Bar," "Options Menu," "System Bar,"
+  "Notifications," and so on. Using Android terms correctly and consistently
+  makes translation easier and results in a better end-product for users.
+</p>
+
+<h4>
+  <strong>Provide sufficient context for declared strings</strong>
+</h4>
+
+<p>
+  As you declare strings in your strings.xml file, make sure to describe the
+  context in which the string is used. This information will be invaluable to
+  translators and result in better quality translation and will also help you
+  manage your strings more effectively over time.
+</p>
+
+<p>
+  Here's an example:
+</p>
+
+<pre class="prettyprint">
+&lt;!-- The action for submitting a form. This text is on a button that can fit 30 chars --&gt;
+&lt;string name="login_submit_button"&gt;Sign in&lt;/string&gt;
+</pre>
+<p>
+  Consider providing context information that may include:
+</p>
+
+<ul>
+  <li>
+    <p>
+      What is this string for? When/where is it presented to the user?
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Where is this in the layout? For example, if it’s a button, translations
+      are less flexible than if it were a text box.
+    </p>
+  </li>
+</ul>
+
+<h4>
+  <strong>Mark message parts that should not be translated</strong>
+</h4>
+
+<p>
+  Often strings contain contain text that shouldn’t be translated to other
+  languages. Common examples might be a piece of code, a placeholder for a
+  value, a special symbol, or a name. As you prepare you strings for
+  translation, look for and mark text that should remain as-is, without
+  translation, so that translators don’t change it.
+</p>
+
+<p>
+  To mark text that should not be translated, use an
+  <code>&lt;xliff:g&gt;</code> placeholder tag. Here's an example tag that
+  ensures the text "%1$s" will not be changed during translation (otherwise it
+  could break the message):
+</p>
+
+<pre class="prettyprint">
+&lt;string name="countdown"&gt;
+    &lt;xliff:g id="time" example="5 days&gt;%1$s&lt;/xliff:g&gt;until holiday
+&lt;/string&gt;
+</pre>
+<p>
+  When you declare a placeholder tag, always add an id attribute that explains
+  what the placeholder is for. If your apps will later replace the placeholder
+  value, be sure to provide an example attribute to clarify the expected use.
+</p>
+
+<p>
+  Here are some more examples of placeholder tags:
+</p>
+
+<pre>
+&lt;resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"&gt;
+
+&lt;!-- Example placeholder for a special unicode symbol --&gt;
+
+&lt;string name="star_rating"&gt;Check out our 5
+
+    &lt;xliff:g id="star"&gt;\u2605&lt;/xliff:g&gt;
+
+&lt;/string&gt;
+
+&lt;!-- Example placeholder for a for a URL --&gt;
+
+&lt;string name="app_homeurl"&gt;
+
+    Visit us at &lt;xliff:g id="application_homepage"&gt;http://my/app/home.html&lt;/xliff:g&gt;
+
+&lt;/string&gt;
+
+&lt;!-- Example placeholder for a name --&gt;
+
+&lt;string name="prod_name"&gt;
+
+    Learn more at &lt;xliff:g id="prod_gamegroup"&gt;Game Group&lt;/xliff:g&gt;
+
+&lt;/string&gt;
+
+&lt;!-- Example placeholder for a literal --&gt;
+
+&lt;string name="promo_message"&gt;
+
+    Please use the "&lt;xliff:g id="promotion_code"&gt;ABCDEFG&lt;/xliff:g&gt;” to get a discount.
+
+&lt;/string&gt;
+
+...
+
+&lt;/resources&gt;
+</pre>
+<h3 class="clearfloat">
+  Related resources
+</h3>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/toolsreference/localizationchecklist/managestrings"
+data-sortorder="-timestamp" data-cardsizes="9x3" data-maxresults="6">
+</div>
+
+<div class="headerLine clearfloat">
+  <h1 id="translate-strings">
+    4. Translate UI strings and other resources
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  Translating your apps’ UI strings and resources to your target languages is
+  the key phase of localization, and it's the one that requires the most care
+  and planning.
+</p>
+
+<p>
+  It is recommended to work with a professional translator (see <a href=
+  "#gp-trans">Purchase professional translations</a>) to ensure high quality
+  translations that enhance the value of your app. Machine translations,
+  although an option may not produce as good an experience for your users.
+</p>
+
+<h4>
+  <strong>Prepare for translation</strong>
+</h4>
+
+<p>
+  Translation output quality will depend in part on your input therefore make
+  sure that your strings.xml file is well organized, well commented, and
+  accurate.
+</p>
+
+<p>
+  Here are some ways to prepare your strings for translation:
+</p>
+
+<ul>
+  <li>
+    <p>
+      Make sure your strings are formatted correctly and consistently.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Follow the strings recommendations listed in <a href=
+      "#manage-strings">Manage strings for localization</a>, above.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Clean up the strings.xml file and remove unused strings.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Place comments in the file to identify the owner, origin, and the version
+      of the file, as well as any special instructions for translators.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Identify existing translations, if any, and include those in an outgoing
+      zip file or other package that you send to translators.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Identify drawables or other resources that require translation and
+      include them in the translators’ package.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Additionally, consider translating your apps’ store listing details
+      &mdash; app title and description, release notes, and so on &mdash; as
+      well as other international marketing materials.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Create a terminology list that explains the meaning and use of key terms
+      found in your product, your market, or the underlying technology. Add the
+      list to the translators’ package.
+    </p>
+  </li>
+</ul>
+
+<h4>
+  <strong>Send your strings for translation</strong>
+</h4>
+
+<p>
+  Early in the development cycle, contact professional translation vendors to
+  get an idea of cost and turnaround time. Make sure to include multiple
+  iterations in the cost. You can find translation vendors online or use
+  translation services available directly from Google Play Developer console
+  (see <a href="#gp-trans">Purchase professional translations</a>).
+</p>
+
+<p>
+  When your translations are complete, take a preliminary look at the
+  translations. Check that all files were translated, check for potential
+  encoding issues, and make sure that declaration formats are intact.
+</p>
+
+<p>
+  If everything looks good, carefully move the localized directories and files
+  back into your apps’ resources. Make sure to tag the directories with the
+  appropriate language and locale qualifiers so that they'll later be loaded
+  properly.
+</p>
+
+<p>
+  After the translations are merged back into your app, start <a href=
+  "#test">testing the localized app</a>.
+</p>
+
+<h4 id="gp-trans">
+  <strong>Purchase professional translations through Google Play</strong>
+</h4>
+
+<div class="sidebox-wrapper">
+  <div class="sidebox">
+    <h2>
+      App Translations Service
+    </h2>
+
+    <p>
+      To make it easy to export your app's strings and import the finished
+      translations into your project, try the <a href=
+      "{@docRoot}sdk/installing/installing-adt.html#tmgr">ADT Translation
+      Manager Plugin</a>.
+    </p>
+  </div>
+</div>
+
+<p>
+  Google Play App Translation Service can help you quickly find and purchase
+  translations of your app. In the Developer Console, you can browse a list of
+  third-party vendors who are pre-qualified by Google to offer high-quality
+  translation at competitive prices. You can upload the strings you want
+  translated, select the languages you want to translate into, and select your
+  translation vendor based on time and price.
+</p>
+
+<p>
+  Once you've purchased translations, you'll receive an email from your vendor.
+  Your translations are a direct business agreement between you and your
+  vendor; you'll need to work directly with the vendor to manage the
+  translation process and deliverables and resolve any support issues.
+</p>
+
+<div>
+  <img src="{@docRoot}images/gp-localization-trans-0.png" class="border-img">
+</div>
+
+<h3>
+  Related resources
+</h3>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/toolsreference/localizationchecklist/translatestrings"
+data-sortorder="-timestamp" data-cardsizes="9x3" data-maxresults="6">
+</div>
+
+<div class="headerLine clearfloat">
+  <h1 id="test">
+    5. Test your localized app
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  Once you've received your translated strings and resources and moved them
+  back into your apps, you need to test the apps to make sure that they’re
+  ready for distribution to your international users.
+</p>
+
+<p>
+  Manual testing can help you discover localization issues in your layouts and
+  strings that can affect user satisfaction and, ultimately, your apps' user
+  rating.
+</p>
+
+<h4>
+  <strong>Set up a test environment</strong>
+</h4>
+
+<p>
+  To test your localized app, you'll need to set up an environment consisting
+  of multiple devices (or virtual devices) and screen sizes, based on the
+  markets and form factors you’re targeting. Note that the range of devices in
+  specific regions might be different. If possible, match your test devices to
+  the actual devices likely to be available to users.
+</p>
+
+<h4>
+  <strong>Look for common localization issues</strong>
+</h4>
+
+<p>
+  On each test device, set the language or locale in Settings. Install and
+  launch the app and then navigate through all of the UI flows, dialogs, and
+  user interactions. Enter text in inputs. Some things to look for include:
+</p>
+
+<ul>
+  <li>
+    <p>
+      Clipped text, or text that overlaps the edge of UI elements or the screen
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Poor line wrapping
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Incorrect word breaks or punctuation
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Incorrect alphabetical sorting
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Incorrect layout direction or text direction
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Untranslated text &mdash; if your default strings are displayed instead
+      of translated strings, then you may have overlooked those strings for
+      translation or marked the resources directory with an incorrect language
+      qualifier.
+    </p>
+  </li>
+</ul>
+
+<p>
+  For cases where your strings have expanded in translation and no longer fit
+  your layouts, it's suggested you try to simplify your default text, simplify
+  your translated text, or adjust your default layouts. If none of those
+  resolves the issue, you can create a custom layout for the language.
+</p>
+
+<h4>
+  <strong>Test for default resources</strong>
+</h4>
+
+<p>
+  After you've tested your apps in all of your supported languages and locales,
+  make sure to test it again in an <em>unsupported language</em> and locale.
+  This’ll help you make sure that your apps includes a full set of default
+  strings and resources, so that your apps are usable to all users, regardless
+  of their preferred language.
+</p>
+
+<h4>
+  <strong>Review with native-language speakers</strong>
+</h4>
+
+<p>
+  During or after testing, it's recommended that you let native speakers review
+  your localized apps. One way to do that is through beta testing with regional
+  users &mdash; Google Play can help you do this. <!-- </p>
+
+<h3 class="clearfloat">Related resources</h3>
+
+<div class="resource-widget resource-flow-layout col-13"
+  data-query="collection:distribute/toolsreference/localizationchecklist/test"
+  data-sortOrder="-timestamp"
+  data-cardSizes="9x3,9x3,6x3,9x3,9x3,9x3"
+  data-maxResults="6"></div> -->
+</p>
+
+<div class="headerLine clearfloat">
+  <h1 id="prepare-launch">
+    6. Prepare for international launch
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  Getting your apps translated is a key part of localization, but to help your
+  product attract users and gain visibility, you should prepare for launch in
+  your target countries and create a broader launch and marketing plan for
+  international users.
+</p>
+
+<h4>
+  <strong>Localize your Google Play listing</strong>
+</h4>
+
+<div class="sidebox-wrapper" style="float:right;">
+  <div class="sidebox">
+    <h2>
+      Localize your Google Play listing
+    </h2>
+
+    <p>
+      Google Play Store listing is the first impression international users
+      will have of your app. You should highlight what's great about your apps
+      to all of your users! Localize your listing in the Developer Console,
+      including:
+    </p>
+
+    <ul>
+      <li>App title and description
+      </li>
+
+      <li>App screenshots on phones and tablets
+      </li>
+
+      <li>Promotional graphics and videos.
+      </li>
+    </ul>
+  </div>
+</div>
+
+<p>
+  If you want your apps to be successful in international markets, it's
+  essential to localize your Google Play store listing. You can manage your
+  localized listing in the Developer Console.
+</p>
+
+<p>
+  Well before launch, decide on your app title, description, promotional text,
+  marketing names and programs, and other text and images. Send your listing
+  text and images for translation early, so that you’ve them ready when beta
+  testing begins. When your translated text is available, you can add it
+  through the Developer Console.
+</p>
+
+<div class="sidebox-wrapper" style="float:right;">
+  <div class="sidebox">
+    <h2>
+      Store listing translation in Google Play
+    </h2>
+
+    <p>
+      You can use the App Translation service on Google Play to translate your
+      store listing. Prepare an XML file with your store listing information
+      and upload just as you would upload the strings.xml file (see <a href=
+      "#gp-trans">Purchase professional translations</a>)
+    </p>
+  </div>
+</div>
+
+<p>
+  Also, since you've made the effort to create a great localized app, let users
+  know about it! Take screenshots of your UI in each language, for phones and
+  7- and 10- inch tablets. You can upload screenshots to the Developer Console
+  for each language you support. These will be of great value to users browsing
+  your app listings in other languages.
+</p>
+
+<p>
+  It's also essential to create localized versions of your promotional graphics
+  and videos. For example, your apps’ feature graphics might include text that
+  should be translated, for maximum effectiveness, or you might want to take a
+  different visual approach in one country than you do in another. You can
+  create different versions of your promotional graphics for each language and
+  upload them to the Developer Console. If you offer a promotional video, you
+  can create localized versions of it and then add a link to the correct
+  localized video for each language you support.
+</p>
+
+<h4>
+  <strong>Plan a beta release in key countries</strong>
+</h4>
+
+<div class="sidebox-wrapper" style="float:right;">
+  <div class="sidebox">
+    <h2>
+      Easy beta testing
+    </h2>
+
+    <p>
+      Google Play now lets you set up groups of alpha and beta testers,
+      anywhere around the world. Check out this powerful feature next time you
+      sign in to the Developer Console.
+    </p>
+  </div>
+</div>
+
+<p>
+  Before launching your apps, it's always valuable to get real-world feedback
+  from users &mdash; even more so when you are launching an app in a new
+  language, country, or region. In those cases, it's highly recommended that
+  you distribute a pre-release version of your apps to users across your key
+  markets and provide an easy means for them to provide feedback and report
+  bugs.
+</p>
+
+<p>
+  Google Play can help you set up a beta program for your apps. After you sign
+  in to the Developer Console and upload your APK, you can set up groups of
+  users for alpha testing and beta testing the app. You can start with a small
+  group of alpha testers, then move to a larger group of beta testers.
+</p>
+
+<p>
+  Once users are added, they access your app's store listing and install the
+  app. <strong>Users on alpha or beta versions cannot leave reviews or
+  ratings</strong>, so there is <strong>no risk to your rating</strong> on
+  Google Play, however it does mean you need to setup a mechanism for your
+  testers to provide you with feedback: consider creating a <a href=
+  "http://www.google.com/+/business/">Google+</a> page or <a href=
+  "https://groups.google.com/forum/#!overview">Google Groups</a>.
+</p>
+
+<p>
+  The feedback you receive will help you adjust your UI, translations, and
+  store listing to ensure a great experience for users.
+</p>
+
+<h4>
+  <strong>Plan for international marketing</strong>
+</h4>
+
+<p>
+  For highest visibility across countries, consider an international marketing
+  or advertising campaign. The scope of the campaign will vary based on the
+  budget you can support, but in general it's cost-effective and productive to
+  do regional or country-specific marketing at launch and after.
+</p>
+
+<h4>
+  <strong>Create localized Google Play badges</strong>
+</h4>
+
+<p>
+  If you’re preparing international marketing, make sure to include a <a href=
+  "{@docRoot}distribute/tools/promote/badges.html">localized Google Play
+  badge</a> to tell users you're on Google Play. You can use the badge
+  generator to quickly build localized badges that you can use on websites or
+  marketing materials. High-resolution assets are also available.
+</p>
+
+<h4>
+  <strong>Create Localized Device Art</strong>
+</h4>
+
+<p>
+  If you feature product shots of your apps running on Android devices, make
+  sure that those shots look great and reflect the latest in Android devices.
+  To help you create high-quality marketing materials, use the drag-and-drop
+  <a href="{@docRoot}distribute/tools/promote/device-art.html">Device Art
+  Generator</a> to quickly frame your screenshot on a Nexus device.
+</p>
+
+<h4>
+  <strong>Check your Optimization Tips</strong>
+</h4>
+
+<p>
+  As you prepare for launch, make sure to sign into the Developer Console and
+  check your apps’ Optimization Tips. The Optimization Tips let you know when
+  you’re missing parts of your localized store listing and provide other
+  helpful reminders for a successful localized launch.
+</p>
+
+<h3>
+  Related resources
+</h3>
+
+<div class="resource-widget resource-flow-layout col-13" data-query=
+"collection:distribute/toolsreference/localizationchecklist/preplaunch"
+data-sortorder="-timestamp" data-cardsizes="9x3,9x3,6x3,9x3,9x3,9x3"
+data-maxresults="6">
+</div>
+
+<div class="headerLine clearfloat">
+  <h1 id="support-users">
+    7. Support international users after launch
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  After you launch your apps internationally, you should be prepared to support
+  users in a variety of languages and time zones. The extent of your
+  international user support depends on your budget, but at a minimum you
+  should watch your ratings, reviews, and download stats carefully after
+  launch.
+</p>
+
+<p>
+  Here are some suggestions:
+</p>
+
+<ul>
+  <li>
+    <p>
+      Use the app stats in the Developer Console to compare your downloads,
+      installs, and uninstalls, and ratings across languages and
+      countries&mdash;If your downloads or ratings aren’t keeping up in
+      specific languages or countries, consider options for improving your
+      product or changing your marketing approach.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Check reviews regularly&mdash;Google Play translates all user reviews for
+      you, so you can stay in touch with how international users feel about
+      your apps, what features they like and what issues are affecting them. By
+      watching reviews, you can spot technical issues that may affect users in
+      a particular country, then fix and update your apps.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Respond to reviews if possible&mdash;It's good to engage with
+      international users in their language or a common language if possible.
+      If not, you can try using translation tools, although results may not be
+      predictable. If your apps gets very popular in a language, consider
+      getting support help from native-language speakers.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Make sure there's a link to any support resources on your website.
+      Consider setting up language-specific user groups, Google+ communities,
+      or other support forums.
+    </p>
+  </li>
+</ul>
+
+<p>
+  By following these practices for localizing your apps, promoting and
+  marketing to international users, and providing ongoing support, you can
+  attract many new users to your apps and maintain their loyalty.
+</p>
+
+<p>
+  Make sure to read the <a href=
+  "{@docRoot}distribute/tools/launch-checklist.html">Launch Checklist</a> to
+  learn more about how to plan, build, and launch your app on Google Play.
+</p>
+<h3 class="clearfloat">Related resources</h3>
+
+<div class="resource-widget resource-flow-layout col-13"
+  data-query="collection:distribute/toolsreference/localizationchecklist/supportlaunch"
+  data-sortOrder="-timestamp"
+  data-cardSizes="9x3,9x3,6x3,9x3,9x3,9x3"
+  data-maxResults="6"></div>
+
diff --git a/docs/html/distribute/tools/open-distribution.jd b/docs/html/distribute/tools/open-distribution.jd
new file mode 100644
index 0000000..f804af2
--- /dev/null
+++ b/docs/html/distribute/tools/open-distribution.jd
@@ -0,0 +1,150 @@
+page.title=Alternative Distribution Options
+page.metaDescription=With Android you can distribute apps to users in any way you want, using any store or distribution approach.
+page.image=/distribute/images/alt-distribution.jpg
+
+@jd:body
+
+<p>
+  As an open platform, Android offers choice. You can distribute your Android
+  apps to users in any way you want, using any distribution approach or
+  combination of approaches that meets your needs. From publishing in an app
+  marketplace to serving your apps from a web site or emailing them directly
+  users, you’re never locked into any particular distribution platform.
+</p>
+
+<p>
+  The process for building and packaging your apps for distribution is the
+  same, regardless of how you distribute them. This saves you time and lets you
+  automate parts of the process as needed. You can read <a href=
+  "{@docRoot}tools/publishing/preparing.html">Preparing for Release</a> for
+  more information.
+</p>
+
+<p>
+  The sections below highlight some of the alternatives for distributing your
+  apps.
+</p>
+
+<div class="headerLine">
+  <h1>
+  Distributing Through an App Marketplace
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  Usually, to reach the broadest possible audience, you’d distribute your apps
+  through a marketplace, such as Google Play.
+</p>
+
+<p>
+  Google Play is the premier marketplace for Android apps and is particularly
+  useful if you want to distribute your apps to a large global audience.
+  However, you can distribute your apps through any app marketplace you want or
+  use multiple marketplaces.
+</p>
+
+<p>
+  Unlike other forms of distribution, Google Play allows you to use the In-app
+  Billing service and Licensing service. The <a href=
+  "{@docRoot}google/play/billing/index.html">In-app Billing service</a> makes
+  it easy to sell in-app products like game jewels or app feature upgrades. The
+  <a href="{@docRoot}google/play/licensing/index.html">Licensing service</a>
+  helps prevent unauthorized installation and use of your apps.
+</p>
+
+<div class="headerLine">
+  <h1>
+  Distributing Your Apps by Email
+  </h1>
+
+  <hr>
+</div>
+
+<div class="figure" style="width:300px;">
+  <img src="{@docRoot}images/publishing/publishing_via_email.png">
+  <p class="img-caption">
+  <b>Figure 1.</b> Users can simply click <b>Install</b> when you send them
+  an application via email.
+  </p>
+</div>
+
+<p>
+  An easy and quick way to release your apps is to send them to users by email.
+  To do this, you prepare the app for release, attach it to an email, and send
+  it to a user. When the user open your email on their Android-powered device,
+  the Android system recognizes the APK and displays an <strong>Install
+  Now</strong> button in the email message (see Figure 1). Users can install
+  your app by touching the button.
+</p>
+
+<p>
+  <strong>Note:</strong> The <strong>Install Now</strong> button, shown in
+  Figure 1, appears only if the user has configured their device to allow
+  installation from <a href=
+  "{@docRoot}distribute/open.html#unknown-sources">unknown sources</a> and
+  opened your email in the native Gmail app.
+</p>
+
+<p>
+  Distributing apps through email is convenient if you’re sending them to a few
+  trusted users, as it provides few protections from piracy and unauthorized
+  distribution; that is, anyone you send your apps to can simply forward them
+  to others.
+</p>
+
+<div class="headerLine">
+  <h1>
+  Distributing Through a Website
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  If you don’t want to release your apps on a marketplace such as Google Play,
+  you can make them available for download on your own website or server,
+  including on a private or enterprise server. To do this, you first prepare
+  your apps for release in the normal way. Then all you need to do is host the
+  release-ready APK file on your website and provide a download link to users.
+</p>
+
+<p>
+  When users browse to the download link from their Android-powered devices,
+  the file is downloaded and Android system automatically starts installing it
+  on the device. However, the installation process will start automatically
+  only if users have configured their Settings to allow the installation of
+  apps from <a href="{@docRoot}distribute/open.html#unknown-sources">unknown
+  sources</a>.
+</p>
+
+<div class="headerLine clearfloat">
+  <h1>
+  User Opt-In for Apps from Unknown Sources
+  </h1>
+
+  <hr>
+</div>
+
+<div class="figure" style="width:325px;">
+  <img src="{@docRoot}images/publishing/publishing_unknown_sources_sm.png">
+  <p class="img-caption">
+  <b>Figure 2.</b> Users must enable the <b>Unknown sources</b> setting
+  before they can install apps not downloaded from Google Play.
+  </p>
+</div>
+
+<p>
+  Android protects users from inadvertent download and install of apps from
+  locations other than Google Play (which is trusted). It blocks such installs
+  until the user opts-in <strong>Unknown sources</strong> in Settings
+  <strong>&gt;</strong> Security, shown in Figure 2. Users need to make this
+  configuration change <em>before</em> they download your apps to their
+  devices.
+</p>
+
+<p>
+  Note that some network providers don’t allow users to install applications
+  from unknown sources.
+</p>
diff --git a/docs/html/distribute/googleplay/promote/badge-files.jd b/docs/html/distribute/tools/promote/badge-files.jd
similarity index 96%
rename from docs/html/distribute/googleplay/promote/badge-files.jd
rename to docs/html/distribute/tools/promote/badge-files.jd
index 03ebd01..cce3632 100644
--- a/docs/html/distribute/googleplay/promote/badge-files.jd
+++ b/docs/html/distribute/tools/promote/badge-files.jd
@@ -1,9 +1,10 @@
 page.title=Google Play Badge Files
+page.image=/images/gp-badges-set.png
+page.metaDescription=Download hi-res assets for localized Google Play badges.
+page.tags="badge, google play"
+
 @jd:body
 
-
-
-
 <style>
 table tr td {border:0}
 </style>
@@ -278,13 +279,13 @@
   </ul>
   
 <p>For more information, see the
-<a href="{@docRoot}distribute/googleplay/promote/brand.html#brand-google_play">Brand
+<a href="{@docRoot}distribute/tools/promote/brand.html#brand-google_play">Brand
 Guidelines</a>.
 
 
 <p>To quickly create a badge that links to your apps on Google Play,
 use the <a
-href="{@docRoot}distribute/googleplay/promote/badges.html">Googe Play badge generator</a>.</p>
+href="{@docRoot}distribute/tools/promote/badges.html">Googe Play badge generator</a>.</p>
     
     
     
\ No newline at end of file
diff --git a/docs/html/distribute/googleplay/promote/badges.jd b/docs/html/distribute/tools/promote/badges.jd
similarity index 94%
rename from docs/html/distribute/googleplay/promote/badges.jd
rename to docs/html/distribute/tools/promote/badges.jd
index 9a32921..e91a804 100644
--- a/docs/html/distribute/googleplay/promote/badges.jd
+++ b/docs/html/distribute/tools/promote/badges.jd
@@ -1,19 +1,25 @@
-page.title=Google Play Badges
+page.title=Google Play Badge Generator
+page.image=/images/gp-badges-set.png
+page.metaDescription=Build badges for your app in just a few clicks, or download hi-res badge assets localized for a variety of languages.
+meta.tags="disttools, promoting, deviceart, marketing, googleplay"
+page.tags="badge, google play"
+
 @jd:body
 
-<p itemprop="description">Google Play badges allow you to promote your app with official branding
-in your online ads, promotional materials, or anywhere else you want a link to your app.</p>
+<p itemprop="description">Google Play badges enable you to promote your apps with
+official branding in your online ads, promotional materials, or anywhere you want
+a link to your apps</p>
 
 <p>In the form below,
 input your app's package name or publisher name, choose the badge style,
 click <em>Build my badge</em>, then paste the HTML into your web content.</p>
 
 <p>If you're creating a promotional web page for your app, you should also use the
-<a href="{@docRoot}distribute/promote/device-art.html">Device Art Generator</a>, which quickly
+<a href="{@docRoot}distribute/tools/promote/device-art.html">Device Art Generator</a>, which quickly
 wraps your screenshots in real device artwork.</p>
 
 <p>For guidelines when using the Google Play badge and other brand assets,
-see the <a href="{@docRoot}distribute/googleplay/promote/brand.html#brand-google_play">Brand
+see the <a href="{@docRoot}distribute/tools/promote/brand.html#brand-google_play">Brand
 Guidelines</a>.</p>
 
 <style type="text/css">
@@ -60,7 +66,7 @@
 var APP_LANGS = ['it','pt-br','pt-pt','nl','ko','ja','fr','es','es-419','en','de'];
 
 // variables for creating 'try it out' demo button
-var imagePath = "https://developer.android.com/images/brand/"
+var imagePath = "{@docRoot}images/brand/"
 var linkStart = "<a href=\"https://play.google.com/store/";
 var imageStart = "\">\n"
         + "  <img alt=\"";
@@ -353,3 +359,4 @@
 <p>Try it out:</p>
 <div id="button-preview" style="margin-top:1em"></div>
 </div>
+
diff --git a/docs/html/distribute/googleplay/promote/brand.jd b/docs/html/distribute/tools/promote/brand.jd
similarity index 92%
rename from docs/html/distribute/googleplay/promote/brand.jd
rename to docs/html/distribute/tools/promote/brand.jd
index 0bda561..2116c0f 100644
--- a/docs/html/distribute/googleplay/promote/brand.jd
+++ b/docs/html/distribute/tools/promote/brand.jd
@@ -1,11 +1,13 @@
 page.title=Brand Guidelines
+page.image=/assets/images/resource-card-default-android.jpg
+page.metaDescription=Guidelines and downloads for the Android and Google Play brands.
+page.tags="brand, bugdroid, assets"
+
 @jd:body
 
-
-
 <p>We encourage you to use the Android and Google Play brands with your Android app
 promotional materials. You can use the icons and other assets on this page
-provided that you follow the guidelines described below.</p>
+provided that you follow the guidelines.</p>
 
 <h2 id="brand-android">Android</h2>
 
@@ -139,11 +141,11 @@
   </div>
          
   <p>The "Get it on Google Play" and "Android App on Google Play" logos are badges that you
-    can use on your web site and promotional materials, to point to your products on Google
+    can use on your website and promotional materials, to point to your products on Google
     Play.</p>
 
   <ul>
-    <li>Do not modify the color, proportions, spacing or any other aspect of the badge image.
+    <li>Don't modify the color, proportions, spacing, or any other aspect of the badge image.
     </li>
     <li>When used alongside logos for other application marketplaces, the Google Play logo
     should be of equal or greater size.</li>
@@ -161,15 +163,15 @@
   
   <p>To quickly create a badge that links to your apps on Google Play,
   use the <a
-  href="{@docRoot}distribute/googleplay/promote/badges.html">Googe Play badge generator</a>
+  href="{@docRoot}distribute/tools/promote/badges.html">Googe Play badge generator</a>
   (provides the badge in over 40 languages).</p>
   
   <p>To create your own size, download an Adobe&reg; Illustrator&reg; (.ai) file for the
-  <a href="{@docRoot}distribute/googleplay/promote/badge-files.html">Google Play
+  <a href="{@docRoot}distribute/tools/promote/badge-files.html">Google Play
   badge in over 40 languages</a>.</p>
     
   <p>For details on all the ways that you can link to your product details page in Google Play, 
-    see <a href="{@docRoot}distribute/googleplay/promote/linking.html">Linking to your products</a></p>
+    see <a href="{@docRoot}distribute/tools/promote/linking.html">Linking to your products</a></p>
 
 
 
diff --git a/docs/html/distribute/promote/device-art-resources/galaxy_nexus/land_back.png b/docs/html/distribute/tools/promote/device-art-resources/galaxy_nexus/land_back.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/galaxy_nexus/land_back.png
rename to docs/html/distribute/tools/promote/device-art-resources/galaxy_nexus/land_back.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/galaxy_nexus/land_fore.png b/docs/html/distribute/tools/promote/device-art-resources/galaxy_nexus/land_fore.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/galaxy_nexus/land_fore.png
rename to docs/html/distribute/tools/promote/device-art-resources/galaxy_nexus/land_fore.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/galaxy_nexus/land_shadow.png b/docs/html/distribute/tools/promote/device-art-resources/galaxy_nexus/land_shadow.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/galaxy_nexus/land_shadow.png
rename to docs/html/distribute/tools/promote/device-art-resources/galaxy_nexus/land_shadow.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/galaxy_nexus/port_back.png b/docs/html/distribute/tools/promote/device-art-resources/galaxy_nexus/port_back.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/galaxy_nexus/port_back.png
rename to docs/html/distribute/tools/promote/device-art-resources/galaxy_nexus/port_back.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/galaxy_nexus/port_fore.png b/docs/html/distribute/tools/promote/device-art-resources/galaxy_nexus/port_fore.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/galaxy_nexus/port_fore.png
rename to docs/html/distribute/tools/promote/device-art-resources/galaxy_nexus/port_fore.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/galaxy_nexus/port_shadow.png b/docs/html/distribute/tools/promote/device-art-resources/galaxy_nexus/port_shadow.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/galaxy_nexus/port_shadow.png
rename to docs/html/distribute/tools/promote/device-art-resources/galaxy_nexus/port_shadow.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/galaxy_nexus/thumb.png b/docs/html/distribute/tools/promote/device-art-resources/galaxy_nexus/thumb.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/galaxy_nexus/thumb.png
rename to docs/html/distribute/tools/promote/device-art-resources/galaxy_nexus/thumb.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_10/land_back.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_10/land_back.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_10/land_back.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_10/land_back.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_10/land_fore.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_10/land_fore.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_10/land_fore.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_10/land_fore.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_10/land_shadow.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_10/land_shadow.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_10/land_shadow.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_10/land_shadow.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_10/port_back.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_10/port_back.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_10/port_back.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_10/port_back.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_10/port_fore.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_10/port_fore.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_10/port_fore.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_10/port_fore.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_10/port_shadow.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_10/port_shadow.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_10/port_shadow.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_10/port_shadow.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_10/thumb.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_10/thumb.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_10/thumb.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_10/thumb.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_4/land_back.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_4/land_back.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_4/land_back.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_4/land_back.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_4/land_fore.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_4/land_fore.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_4/land_fore.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_4/land_fore.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_4/land_shadow.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_4/land_shadow.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_4/land_shadow.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_4/land_shadow.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_4/port_back.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_4/port_back.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_4/port_back.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_4/port_back.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_4/port_fore.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_4/port_fore.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_4/port_fore.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_4/port_fore.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_4/port_shadow.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_4/port_shadow.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_4/port_shadow.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_4/port_shadow.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_4/thumb.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_4/thumb.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_4/thumb.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_4/thumb.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_5/land_back.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_5/land_back.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_5/land_back.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_5/land_back.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_5/land_fore.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_5/land_fore.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_5/land_fore.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_5/land_fore.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_5/land_shadow.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_5/land_shadow.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_5/land_shadow.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_5/land_shadow.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_5/port_back.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_5/port_back.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_5/port_back.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_5/port_back.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_5/port_fore.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_5/port_fore.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_5/port_fore.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_5/port_fore.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_5/port_shadow.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_5/port_shadow.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_5/port_shadow.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_5/port_shadow.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_5/thumb.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_5/thumb.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_5/thumb.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_5/thumb.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_7/land_back.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_7/land_back.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_7/land_back.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_7/land_back.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_7/land_fore.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_7/land_fore.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_7/land_fore.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_7/land_fore.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_7/land_shadow.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_7/land_shadow.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_7/land_shadow.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_7/land_shadow.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_7/port_back.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_7/port_back.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_7/port_back.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_7/port_back.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_7/port_fore.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_7/port_fore.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_7/port_fore.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_7/port_fore.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_7/port_shadow.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_7/port_shadow.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_7/port_shadow.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_7/port_shadow.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_7/thumb.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_7/thumb.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_7/thumb.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_7/thumb.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_7_2012/land_back.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_7_2012/land_back.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_7_2012/land_back.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_7_2012/land_back.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_7_2012/land_fore.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_7_2012/land_fore.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_7_2012/land_fore.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_7_2012/land_fore.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_7_2012/land_shadow.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_7_2012/land_shadow.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_7_2012/land_shadow.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_7_2012/land_shadow.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_7_2012/port_back.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_7_2012/port_back.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_7_2012/port_back.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_7_2012/port_back.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_7_2012/port_fore.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_7_2012/port_fore.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_7_2012/port_fore.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_7_2012/port_fore.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_7_2012/port_shadow.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_7_2012/port_shadow.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_7_2012/port_shadow.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_7_2012/port_shadow.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_7_2012/thumb.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_7_2012/thumb.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_7_2012/thumb.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_7_2012/thumb.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_s/land_back.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_s/land_back.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_s/land_back.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_s/land_back.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_s/land_fore.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_s/land_fore.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_s/land_fore.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_s/land_fore.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_s/land_shadow.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_s/land_shadow.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_s/land_shadow.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_s/land_shadow.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_s/port_back.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_s/port_back.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_s/port_back.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_s/port_back.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_s/port_fore.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_s/port_fore.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_s/port_fore.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_s/port_fore.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_s/port_shadow.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_s/port_shadow.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_s/port_shadow.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_s/port_shadow.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/nexus_s/thumb.png b/docs/html/distribute/tools/promote/device-art-resources/nexus_s/thumb.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/nexus_s/thumb.png
rename to docs/html/distribute/tools/promote/device-art-resources/nexus_s/thumb.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/xoom/land_back.png b/docs/html/distribute/tools/promote/device-art-resources/xoom/land_back.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/xoom/land_back.png
rename to docs/html/distribute/tools/promote/device-art-resources/xoom/land_back.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/xoom/land_fore.png b/docs/html/distribute/tools/promote/device-art-resources/xoom/land_fore.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/xoom/land_fore.png
rename to docs/html/distribute/tools/promote/device-art-resources/xoom/land_fore.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/xoom/land_shadow.png b/docs/html/distribute/tools/promote/device-art-resources/xoom/land_shadow.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/xoom/land_shadow.png
rename to docs/html/distribute/tools/promote/device-art-resources/xoom/land_shadow.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/xoom/port_back.png b/docs/html/distribute/tools/promote/device-art-resources/xoom/port_back.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/xoom/port_back.png
rename to docs/html/distribute/tools/promote/device-art-resources/xoom/port_back.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/xoom/port_fore.png b/docs/html/distribute/tools/promote/device-art-resources/xoom/port_fore.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/xoom/port_fore.png
rename to docs/html/distribute/tools/promote/device-art-resources/xoom/port_fore.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/xoom/port_shadow.png b/docs/html/distribute/tools/promote/device-art-resources/xoom/port_shadow.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/xoom/port_shadow.png
rename to docs/html/distribute/tools/promote/device-art-resources/xoom/port_shadow.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art-resources/xoom/thumb.png b/docs/html/distribute/tools/promote/device-art-resources/xoom/thumb.png
similarity index 100%
rename from docs/html/distribute/promote/device-art-resources/xoom/thumb.png
rename to docs/html/distribute/tools/promote/device-art-resources/xoom/thumb.png
Binary files differ
diff --git a/docs/html/distribute/promote/device-art.jd b/docs/html/distribute/tools/promote/device-art.jd
similarity index 97%
rename from docs/html/distribute/promote/device-art.jd
rename to docs/html/distribute/tools/promote/device-art.jd
index b3b414e..b0b5f84 100644
--- a/docs/html/distribute/promote/device-art.jd
+++ b/docs/html/distribute/tools/promote/device-art.jd
@@ -1,9 +1,13 @@
 page.title=Device Art Generator
+page.image=/images/device-art-ex-crop.jpg
+page.metaDescription=Drag and drop screenshots of your app into real device artwork, for better looking promotional images and improved visual context.
+meta.tags="disttools, promoting, deviceart, marketing"
+page.tags="device, deviceart, nexus, assets"
+Xnonavpage=true
+
 @jd:body
 
-<p>The device art generator allows you to quickly wrap your app screenshots in real device artwork.
-This provides better visual context for your app screenshots on your web site or in other
-promotional materials.</p>
+<p>The device art generator enables you to quickly wrap app screenshots in real device artwork. This provides better visual context for your app screenshots on your website or in other promotional materials</p>
 
 <p class="note"><strong>Note</strong>: Do <em>not</em> use graphics created here in your 1024x500
 feature image or screenshots for your Google Play app listing.</p>
diff --git a/docs/html/distribute/googleplay/promote/linking.jd b/docs/html/distribute/tools/promote/linking.jd
similarity index 95%
rename from docs/html/distribute/googleplay/promote/linking.jd
rename to docs/html/distribute/tools/promote/linking.jd
index 4fdc5db..025480b 100644
--- a/docs/html/distribute/googleplay/promote/linking.jd
+++ b/docs/html/distribute/tools/promote/linking.jd
@@ -1,4 +1,9 @@
 page.title=Linking to Your Products
+page.image=/images/gp-linking-ex-crop.png
+meta.tags="promoting"
+page.tags="linking"
+page.metaDescription=Learn how to build links that take users to your published apps in Google Play from browse or search.
+
 @jd:body
 
 <div class="sidebox-wrapper">
@@ -25,7 +30,7 @@
 
 <p>If you are linking from an Android app, you can also control whether the link
 launches the Play Store application or the browser, which takes the user
-to the Google Play web site.</p>
+to the Google Play website.</p>
 
 <h2 id="OpeningDetails">Linking to a Product Details Page</h2>
 
@@ -173,7 +178,7 @@
 and <code>market://</code> for links in Android apps.</p>
 
 <p>If you want to link to your products from an Android app, create an {@link
-android.content.Intent} that opens an Google Play URL, as shown in the example
+android.content.Intent} that opens a Google Play URL, as shown in the example
 below.</p>
 
 <pre>
diff --git a/docs/html/distribute/users/build-buzz.jd b/docs/html/distribute/users/build-buzz.jd
new file mode 100644
index 0000000..b76498e
--- /dev/null
+++ b/docs/html/distribute/users/build-buzz.jd
@@ -0,0 +1,301 @@
+page.title=Build Buzz
+page.image=/distribute/images/build-buzz.jpg
+page.metaDescription=Generate interest and demand for your app. Here are some ways to help users find, download, and install your apps.
+page.tags="users, growth, promotion"
+
+@jd:body
+
+<div id="qv-wrapper">
+  <div id="qv">
+    <h2>
+      Contents
+    </h2>
+
+    <ol>
+      <li>
+        <a href="#link-to-your-apps">Link to Your Apps</a>
+      </li>
+      <li>
+        <a href="#use-the-google-play-badge">Use the Badge</a>
+      </li>
+      <li>
+        <a href="#cross-promote-from-your-other-apps">Cross-Promote Your Apps</a>
+      </li>
+      <li>
+        <a href="#hold-a-contest">Hold a Contest</a>
+      </li>
+      <li>
+        <a href="#leverage-pr">Leverage PR</a>
+      </li>
+      <li>
+        <a href="#use-social-media">Use Social Media</a>
+      </li>
+      <li>
+        <a href="#publish-youtube-videos">Publish YouTube Videos</a>
+      </li>
+      <li>
+        <a href="#advertise">Advertise</a>
+      </li>
+      <li>
+        <a href="#maximize-your-marketing-spend">Maximize Your Marketing
+        spend</a>
+      </li>
+      <li><a href="#related-resources">Related Resources</a></li>
+    </ol>
+  </div>
+</div>
+
+<div style="float:right;border 2px solid #ddd;">
+  <img src="{@docRoot}distribute/images/build-buzz.jpg" style=
+  "width:240px;margin:0 0 1.5em 1em;">
+</div>
+
+<p>
+  With more apps published each week in Google Play, building  buzz
+  around your own apps helps them get noticed and makes it easier for
+  users to find and download them.
+</p>
+
+<p>
+  Building buzz doesn’t have a single formula. The tools and techniques
+  described here have worked for other developers, but finding the right mix
+  will depend on your apps, your audience, and your competition. And don’t be
+  afraid to try something different or quirky, taking a risk could pay big
+  dividends.
+</p>
+
+<div class="headerLine">
+  <h1 id="link-to-your-apps">
+    Link to Your Apps in Google Play
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  After publishing your apps, you can take Android users directly to your
+  app/games detail page on Google Play by <a href=
+  "{@docRoot}distribute/tools/promote/linking.html">providing links</a> in your
+  social network posts, ad campaigns, app reviews and articles, your website,
+  and more.
+</p>
+
+<p>
+  You can also link to:
+</p>
+
+<ul>
+  <li>A <a href=
+  "{@docRoot}distribute/tools/promote/linking.html#OpeningPublisher">list</a>
+  of all of your apps
+  </li>
+
+  <li>A Google Play <a href=
+  "{@docRoot}distribute/tools/promote/linking.html#PerformingSearch">search
+  result</a>
+  </li>
+
+  <li>A <a href=
+  "{@docRoot}distribute/tools/promote/linking.html#OpeningCollection">collection</a>
+  on Google Play
+  </li>
+</ul>
+
+<div class="headerLine clearfloat">
+  <h1 id="use-the-google-play-badge">
+    Use the Google Play Badge
+  </h1>
+
+  <hr>
+</div>
+
+<div class="figure" style="margin:0 3em;">
+  <img src="{@docRoot}images/gp-build-buzz-uplift-1.png">
+</div>
+
+<p>
+  <a href="{@docRoot}distribute/tools/promote/badges.html">Google Play
+  badges</a> are an especially great way let Android users know that your apps
+  are available and link them directly to your Google Play page. Users are more
+  likely to download and trust your apps and games when the Google Play badge
+  is used.
+</p>
+
+<p>Badge your
+  websites, collateral, and ad campaigns. With the badge generator, they're
+  also easy to make and available in multiple languages.
+</p>
+
+<div class="headerLine clearfloat">
+  <h1 id="cross-promote-from-your-other-apps">
+    Cross-Promote from Your Other Apps
+  </h1>
+
+  <hr>
+</div>
+
+<div class="figure-right">
+  <img src="{@docRoot}images/gp-buzz-1.jpg">
+  <p class="img-caption">
+    Cross-promoting related apps.
+  </p>
+</div>
+
+<p>
+  Cross promoting, or house ads, is a great cost effective way to get users to
+  try out new titles. Be sure that your house ad is unobtrusive and presented
+  at a time convenient for users to leave your apps and try out your new title.
+  Also, be sure to include logic that allows users to dismiss the ad and
+  control if they will be asked again later.
+</p>
+
+<p>
+  Consider using free AdMob <a href=
+  "https://support.google.com/admob/v2/answer/3210452?hl=en#subid=us-en-et-dac">
+  house ads</a> within your apps to create awareness and promote your entire
+  portfolio of apps. When launching new apps, an easy way to quickly attract
+  users is to promote directly to your existing customers.
+</p>
+
+<div class="headerLine">
+  <h1 id="hold-a-contest">
+    Hold a Contest
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  Contests can be a great way to engage your users. If you have a game, hold a
+  tournament and promote it through your marketing channels. Use Google Play
+  Games APIs for leaderboards and achievements to stimulate competition. Some
+  app developers have provided prizes for creative uses of an app or social
+  engagement. For example, a photo app developer can hold a photo contest.
+</p>
+
+<p>
+  But be sure you’re complying with the appropriate legal requirements in your
+  country and provide a clear set of terms and conditions, accessible online.
+  Don’t let a lack of attention to detail spoil a great marketing opportunity.
+</p>
+
+<div class="headerLine">
+  <h1 id="leverage-pr">
+    Leverage PR
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  Public Relations outreach can be a valuable marketing initiative. Many
+  developers use PR to announce new features in their apps or games, which, in
+  turn, builds demand for the updated release when it comes out. You can also
+  provide early copies of your app or game for the press to review, and publish
+  their reviews when the app or game launches.
+</p>
+
+<div class="headerLine">
+  <h1 id="use-social-media">
+    Use Social Media
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  Social media is your opportunity to build promotion for your apps. Start with
+  your own channels: update users on your plans before launch, announce your
+  launch, and talk about progress after launch (downloads, new features, and
+  alike.) Then expand by encouraging your users to forward and share your
+  posts.
+</p>
+
+<p>
+  Take advantage of bloggers. Look for bloggers that cover Android and learn
+  what interest them. Remember to look locally as well as globally, gaining a
+  local following can be a great springboard to global success. When you’ve
+  selected a target group of bloggers focus on them by sending details of your
+  apps and free versions if the apps are priced. Follow up and ask them to
+  review your apps. A review on the right blog is a great promotion.
+</p>
+
+<div class="headerLine clearfloat">
+  <h1 id="publish-youtube-videos">
+    Publish YouTube Videos
+  </h1>
+
+  <hr>
+</div>
+
+<div class="center-img" style="padding-top:1em;">
+  <img src="{@docRoot}images/gp-build-buzz-yt.png">
+</div>
+
+<p>
+  YouTube videos are now an essential part of building buzz. Use them to
+  showcase your apps’ feature. Remember to do this before, at, and after
+  launch. Taking users on a journey through the development of your apps can be
+  a great way to drive downloads at launch.
+</p>
+
+<div class="headerLine">
+  <h1 id="advertise">
+    Advertise
+  </h1>
+
+  <hr>
+</div>
+
+<div class="figure">
+  <img src="{@docRoot}images/google/gps-ads.png" style="width:340px">
+</div>
+
+<p>
+  Advertise your app in other apps to increase downloads. There are many tools
+  to help you target the right users for your apps and games. You can use
+  <a href=
+  "http://www.google.com/ads/admob/promote.html#subid=us-en-et-dac">AdMob</a>
+  to drive installs of your app at a target cost-per-acquisition (CPA). You
+  also get free house ads for your own app. <a href=
+  "https://apps.admob.com/admob/signup?subid=us-en-et-dac&amp;_adc=ww-ww-et-admob2&amp;hl=en">
+  Sign up for an AdMob account</a> to get started.
+</p>
+
+<div class="headerLine clearfloat">
+  <h1 id="maximize-your-marketing-spend">
+    Maximize your Marketing Spend
+  </h1>
+
+  <hr>
+</div>
+
+<div class="figure" style="margin: 0 3em;">
+  <img src="{@docRoot}images/gp-build-buzz-uplift-2.png" style="">
+</div>
+
+<p>
+  Maximize buzz and leverage the halo effect of cross-platform, multimedia,
+  simultaneous launches.
+</p>
+
+<p><strong>Developers who launch on multiple platforms at
+  the same time have received a 10-20% uplift.</strong>If you’re spending money
+  to advertise your launch or spending effort on press, shipping on multiple
+  platforms simultaneously helps you maximize your return on investment.
+</p>
+
+<div class="headerLine clearfloat">
+  <h1 id="related-resources">
+    Related Resources
+  </h1>
+
+  <hr>
+</div>
+
+<div class="resource-widget resource-flow-layout col-13"
+  data-query="collection:distribute/users/buildbuzz"
+  data-sortOrder="-timestamp"
+  data-cardSizes="9x3"
+  data-maxResults="6"></div>
+
diff --git a/docs/html/distribute/users/build-community.jd b/docs/html/distribute/users/build-community.jd
new file mode 100644
index 0000000..1623939
--- /dev/null
+++ b/docs/html/distribute/users/build-community.jd
@@ -0,0 +1,202 @@
+page.title=Build Community
+page.metaDescription=Build a loyal following with great support and communication.
+page.tags="users, growth, community"
+
+@jd:body
+
+<div id="qv-wrapper">
+  <div id="qv">
+  <h2>
+    Contents
+  </h2>
+
+  <ol>
+    <li>
+    <a href="#starting-your-community">Starting Your Community</a>
+    </li>
+
+    <li>
+    <a href="#tools-to-build-your-community">Tools to Build Your Community</a>
+    </li>
+
+    <li>
+    <a href="#managing-your-community">Managing Your Community</a>
+    </li>
+    <li>
+    <a href="#related-resources">Related Resources</a>
+    </li>
+  </ol>
+  </div>
+</div>
+
+<p>
+  Fans of your apps love to help others, turn newer users into fans, and bring
+  you more users as they talk about your app. Building a community can help you
+  tap into those influencers to help you improve your app and provide support
+  to others.
+</p>
+
+<p>
+  Building your own community can help you bring content that will delight
+  users and get them talking about your apps to friends, family and others in
+  their social network.
+</p>
+
+<div class="headerLine">
+  <h1 id="starting-your-community">
+  Starting Your Community
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  In conjunction with your apps’ design and development, you should start
+  defining and building your community infrastructure. There’s no one approach
+  that fits all, and the approach for each of your apps may need to be a little
+  different. You should start by thinking about your potential users and asking
+  questions such as:
+</p>
+
+<ul>
+  <li>
+  <p>
+    How will my users prefer to interact? Game users may prefer a modern feed
+    style community, users of a financial management app a more traditional
+    discussion forum.
+  </p>
+  </li>
+
+  <li>
+  <p>
+    Should I have a community for all my apps or should each app have its
+    own? Will users be turned off if the community isn’t just about the app
+    that interests them or can I make it a way to turn them onto my other
+    apps?
+  </p>
+  </li>
+
+  <li>
+  <p>
+    Will different countries or territories, or speakers of particular
+    languages need separate forums? How will I handle feedback in languages I
+    don’t know?
+  </p>
+  </li>
+
+  <li>
+  <p>
+    Do I need any additional policies beyond those governing the tool used to
+    host the community?
+  </p>
+  </li>
+</ul>
+
+<p>
+  Any way you do it, starting your community early helps you build momentum as
+  you turn happy users into influencers.
+</p>
+
+<p>
+  Consider inviting your existing users through a rich notification or an
+  opt-in on your website. Don’t overlook inviting your critics too. If you have
+  been able to address their earlier issues you may convert them into
+  supporters — it’s not unknown for your harshest critics to become your most
+  enthusiastic fans if you address their concerns.
+</p>
+
+<p>
+  When you use the <a href=
+  "{@docRoot}distribute/googleplay/developer-console.html#alpha-beta">beta-testing
+  feature</a> in Google Play, you’ll create a testers group through a <a href=
+  "https://support.google.com/groups/answer/46601">Google Group</a> or <a href=
+  "https://support.google.com/plus/topic/2888488">Google+ Community</a> to
+  define who gets your software for testing. Consider managing these groups as
+  communities in their own right.
+</p>
+
+<div class="headerLine">
+  <h1 id="tools-to-build-your-community">
+  Tools to Build Your Community
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  There are many tools you can use to build your community. Before you launch,
+  inviting <a href="http://www.google.com/+/business/">Google+</a> users or
+  <a href="https://support.google.com/groups/answer/46601?hl=en">Google
+  Groups</a> to <a href=
+  "{@docRoot}distribute/googleplay/developer-console.html#alpha-beta">beta-test</a>
+  your app can help you kickstart your community while you listen to and
+  respond to your user feedback.
+</p>
+
+<p>
+  Once you’ve launched, your Google+ or other social media presence can help
+  you continue to gather feedback, answer questions, and get input on updates.
+  Use social media to get the conversation started. Post updates to your
+  followers, announce new apps, and host contests. Ask followers to re-post so
+  that they bring new users into the conversation. Fans love to profess their
+  passion for great apps, so be sure to give them plenty of reason to do so.
+</p>
+
+<p>
+  Forums like <a href=
+  "https://support.google.com/groups/answer/46601?hl=en">Google Groups</a> are
+  particularly well suited to help you and your users provide support to
+  others. By helping out your community, you’re building your fan base who will
+  share their experiences with other prospective customers.
+</p>
+
+<p>
+  Respond to comments and reviews on both your product details page on Google
+  Play and <a href="http://youtube.com">YouTube</a> pages. Prospective
+  customers are influenced by reviews and comments, so be sure to manage your
+  brand in every channel you can.
+</p>
+
+<div class="headerLine">
+  <h1 id="managing-your-community">
+  Managing Your Community
+  </h1>
+
+  <hr>
+</div>
+
+<div class="figure">
+  <img src="{@docRoot}images/gp-community-0.png">
+</div>
+
+<p>
+  Engaged users want you to succeed. Let them know you’re listening! Responding
+  to posts, comments, and other social media mentions improves your ratings by
+  letting users know you care.
+</p>
+
+<p>
+  Update the product based on user feedback and announce new releases. Users
+  often change their original star ratings after feeling heard, inspiring more
+  users to install your apps.
+</p>
+
+<p>
+  There are many ways to make your community feel special. Consider polls to
+  let users influence product updates. Use competitions to inspire and reward
+  your community. Giving a special <em>member of the week</em> badge is an easy
+  way to recognize those that help others. Or get users involved in testing new
+  versions or new apps to make them feel special.
+</p>
+
+<div class="headerLine clearfloat">
+  <h1 id="related-resources">
+  Related Resources
+  </h1>
+  <hr>
+</div>
+<div class="resource-widget resource-flow-layout col-13"
+  data-query="collection:distribute/users/buildcommunity"
+  data-sortOrder="-timestamp"
+  data-cardSizes="9x3"
+  data-maxResults="6"></div>
\ No newline at end of file
diff --git a/docs/html/distribute/users/expand-to-new-markets.jd b/docs/html/distribute/users/expand-to-new-markets.jd
new file mode 100644
index 0000000..cc94a92
--- /dev/null
+++ b/docs/html/distribute/users/expand-to-new-markets.jd
@@ -0,0 +1,325 @@
+page.title=Expand Into New Markets
+page.metaDescription=Tap fast-growing markets in Japan, Korea, India, Brazil, and many other countries around the world.
+page.image=/distribute/images/expand-into-new-markets.jpg
+page.tags="users, growth, global"
+
+@jd:body
+
+<div id="qv-wrapper">
+  <div id="qv">
+    <h2>
+      Contents
+    </h2>
+
+    <ol>
+      <li>
+        <a href="#localize-your-product">Localize Your Product</a>
+      </li>
+
+      <li>
+        <a href="#testing-and-support">Testing and Support</a>
+      </li>
+
+      <li>
+        <a href="#localize-your-google-play-listing">Localize Your Store
+        Listing</a>
+      </li>
+
+      <li>
+        <a href="#marketing">Marketing</a>
+      </li>
+
+      <li>
+        <a href="#related-resources">Related Resources</a>
+      </li>
+    </ol>
+  </div>
+</div>
+<p>
+  Android and Google Play give you a worldwide audience for your apps, with an
+  addressable user base that's growing very rapidly in countries such as Japan,
+  Korea, India, and Brazil. You can sell your app in more than 130 countries.
+</p>
+
+<p>
+  To <strong>maximize your app's distribution potential and earn high
+  ratings</strong> from users around the world, we encourage you to localize
+  your app. Once you’ve built a solid foundation in your home market, take
+  advantage of Android’s powerful growth around the world and expand your app
+  to new markets.
+</p>
+
+<div class="sidebox-wrapper" style="float:right;">
+  <div class="sidebox">
+    <p>
+      <strong>Tip:</strong> Localization is more than translation. Plan product
+      features, launch, and marketing for key markets.
+    </p>
+  </div>
+</div>
+
+<p class="caution" style="font-size:15.5px;">
+</p>
+
+<p>
+  Localization involves a variety of tasks throughout your app development
+  cycle, and advance planning is essential. But <strong>localization is more
+  than just translating your UI</strong>. To be successful, you also need to
+  localize your Google Play listing and ensure your marketing is suitable for
+  the demographic you’re addressing.
+</p>
+
+<p>
+  To reduce development and maintenance effort, use a single APK for all
+  regions. A single APK also allows you to more easily track metrics by
+  country. Google Play takes care of providing the appropriate localized
+  version of your app based on user location.
+</p>
+
+<div class="headerLine">
+  <h1 id="localize-your-product">
+    Localize Your Product
+  </h1>
+
+  <hr>
+</div>
+
+<div class="sidebox-wrapper" style="float:right;">
+  <div class="sidebox">
+    <p>
+      <strong>Tip:</strong> Use a professional translation service located in
+      your target country to ensure high quality and good user ratings.
+    </p>
+  </div>
+</div>
+
+<p>
+  The first step is to identify your target markets and associated languages,
+  then focus your product localization on those countries. Some of the tasks
+  include translating your UI strings and localizing dates and times, layouts,
+  text direction, and finally your Google Play store listing. To learn more
+  about how to localize your app, visit our <a href=
+  "{@docRoot}distribute/tools/localization-checklist.html">Localization
+  Checklist</a>.
+</p>
+<!-- <p>[Need graphic highlighting that it’s all about getting high ratings]</p> -->
+
+<p>
+  Work with a professional translator, preferably located in the country you’re
+  localizing your apps for, to ensure high quality results. Machine
+  translations may affect your apps’ ratings, as they’re less reliable than
+  high-quality professional translations. For example, a professional service
+  will know to consider the vocabulary expansion, left-to-right and
+  right-to-left support, and other factors in each language. Learn more about
+  UI considerations and other factors in the <a href=
+  "{@docRoot}distribute/tools/localization-checklist.html#design">Design for
+  Localization</a> section of the Localization Checklist.
+</p>
+
+<p>
+  <strong>Google Play App Translation Service</strong> can help you quickly
+  find and purchase translations of your apps. In the <a href=
+  "https://play.google.com/apps/publish/">Developer Console</a>, you can browse
+  a list of third-party vendors who are pre-qualified by Google to offer
+  high-quality professional translations at competitive prices.
+</p>
+
+<div style="float:left; width:48%; padding:8px;">
+  <img src="{@docRoot}images/gp-listing-3.jpg">
+</div>
+
+<div style="width:48%; padding:8px; float:left">
+  <img src="{@docRoot}images/gp-expand-2.jpg">
+</div>
+
+<div class="headerLine clearfloat">
+  <h1 id="testing-and-support">
+    Testing and Support
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  Before you launch, be sure to use our <a href=
+  "{@docRoot}distribute/googleplay/developer-console.html#alpha-beta">beta
+  testing</a> and <a href=
+  "{@docRoot}distribute/googleplay/developer-console.html#staged-rollouts">staged
+  rollouts</a> to identify and address issues before users can rate your app.
+  Feedback can be gathered using a <a href=
+  "https://support.google.com/groups/answer/46601">Google Group</a> or <a href=
+  "https://support.google.com/plus/topic/2888488">Google+ Community</a>. Watch
+  user sentiment and respond if necessary as you add countries.
+</p>
+
+<p>
+  After you launch, <strong>offer support hours in the local time zone in the
+  local language</strong>. When possible, having a local presence can
+  dramatically increase your daily active users and revenue. For example,
+  <a href="">this developer</a> was able to <strong>increase their revenue over
+  500% after creating a local presence</strong> in Asia and taking great care
+  of their users.
+</p>
+
+<div class="headerLine">
+  <h1 id="localize-your-google-play-listing">
+    Localize Your Google Play Store Listing
+  </h1>
+
+  <hr>
+</div>
+
+<div class="sidebox-wrapper" style="float:right;">
+  <div class="sidebox">
+    <p>
+      <strong>Tip:</strong> You can select regions, set regional pricing, and
+      localize your listing while maintaining only one APK.
+    </p>
+  </div>
+</div>
+
+<div class="figure">
+  <img src="{@docRoot}images/gp-buyer-currency.png" class="border-img">
+</div>
+
+<p>
+  Within your Google Play listing, you’ll need to set the regions in which your
+  apps will be available, set pricing for each, and customize your Google Play
+  listing to ensure it speaks to local audiences. You can change your country
+  and carrier targeting at any time just by saving changes in the Google Play
+  Developer Console.
+</p>
+
+<h3>
+  Region selection
+</h3>
+
+<p>
+  In the Developer Console, you can set the regions you make your app available
+  to, pricing in local currencies, and all Google Play listing marketing. You
+  can specify which countries and territories you want to distribute to, and
+  even which carriers (for some countries).
+</p>
+
+<h3>
+  Pricing
+</h3>
+
+<p>
+  When you start to address new markets you have several options for setting
+  the prices of your products: apps, in-app products, and subscriptions. You
+  can set a default price for each product and allow Google Play to adjust this
+  each month for changes in exchange rates, or manually set prices.
+</p>
+
+<p>
+  There are several reasons why it might be beneficial to set prices manually,
+  such as:
+</p>
+
+<ul>
+  <li>
+    <p>
+      Cost of living differences. To better target developing markets you may
+      consider offering your apps at a lower price to make them more affordable
+      in relation to local incomes.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Price perception. Users in some countries respond well to prices set to
+      x.99, while others prefer x.00 pricing.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Numerology. You may wish to avoid using certain numbers that are
+      considered unlucky, such as 13 or 4.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Competition. Your app may have local competition in some markets that you
+      need to account for.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Local trends and interests. Your apps may be able to bear a higher price
+      in some markets. For example, the interest in various sports varies
+      greatly from country to country.
+    </p>
+  </li>
+</ul>
+
+<p>
+  You may also want to run short-term promotions and discounts in specific
+  countries.
+</p>
+
+<p>
+  The <a href=
+  "{@docRoot}distribute/googleplay/developer-console.html#selling-pricing-your-products">
+  Pricing &amp; Distribution</a> section in the <a href=
+  "https://play.google.com/apps/publish/">Developer Console</a> is where you
+  set and manage regional distribution and local prices.
+</p>
+
+<h3>
+  Copy and creative
+</h3>
+
+<p>
+  To market to users around the world, <strong>localize your store listing,
+  including app details and description, promotional graphics, screenshots, and
+  more.</strong> Graphical assets and copy can be uploaded for each country you
+  are targeting.
+</p>
+
+<div>
+  <img src="{@docRoot}images/gp-expand-4.jpg" class="border-img">
+</div>
+
+<div>
+  <img src="{@docRoot}images/gp-expand-5.jpg" class="border-img">
+</div>
+
+<p>
+  Learn more about how to localize your <a href=
+  "{@docRoot}distribute/tools/launch-checklist.html#prepare-graphics">store
+  listing</a>.
+</p>
+
+<div class="headerLine">
+  <h1 id="marketing">
+    Marketing
+  </h1>
+
+  <hr>
+</div>
+
+<div class="figure">
+  <img src="{@docRoot}images/gp-badge-jp.png">
+</div>
+
+<p>
+  Just like your Google Play listing, all other marketing should be localized
+  to speak to the local audience. This includes images, colors, icons, and
+  audio. To maximize effectiveness, <strong>run promotions, contests, and
+  announcements at local time</strong>. You can build a localized <a href=
+  "{@docRoot}distribute/tools/promote/badges.html">Google Play badge</a> and
+  <a href="{@docRoot}distribute/tools/promote/device-art.html">device art</a>
+  for each language you support.
+</p>
+
+<div class="headerLine clearfloat"><h1 id="related-resources">Related Resources</h1><hr></div>
+
+<div class="resource-widget resource-flow-layout col-13"
+  data-query="collection:distribute/getusers/expandnewmarkets"
+  data-sortOrder="-timestamp"
+  data-cardSizes="6x3,6x3,6x3,6x3,6x3,6x3"
+  data-maxResults="6"></div>
diff --git a/docs/html/distribute/users/index.jd b/docs/html/distribute/users/index.jd
new file mode 100644
index 0000000..77ef609
--- /dev/null
+++ b/docs/html/distribute/users/index.jd
@@ -0,0 +1,30 @@
+page.title=Get Users
+section.landing=true
+nonavpage=true
+
+@jd:body
+
+<p>
+  You’ve published your app, now how do you acquire users? Every app and game
+  is different, but there are some common themes from successful Google Play
+  developers. These best practices are critical to your app or game’s success.
+</p>
+
+<div class="dynamic-grid">
+
+<div class="resource-widget resource-flow-layout landing col-16"
+  data-query="collection:distribute/users"
+  data-cardSizes="6x6, 6x6, 6x6, 9x6, 9x6, 6x6, 6x6, 6x6"
+  data-maxResults="8">
+</div>
+
+<h3>Related resources</h3>
+
+  <div class="resource-widget resource-flow-layout col-16"
+    data-query="type:youtube+tag:users,tag:global,type:blog+tag:users"
+    data-sortOrder="-timestamp"
+    data-cardSizes="6x3"
+    data-maxResults="6">
+  </div>
+  
+</div>
diff --git a/docs/html/distribute/users/know-your-user.jd b/docs/html/distribute/users/know-your-user.jd
new file mode 100644
index 0000000..fb91a05
--- /dev/null
+++ b/docs/html/distribute/users/know-your-user.jd
@@ -0,0 +1,153 @@
+page.title=Know Your User
+page.metaDescription=It\'s essential to understand your users and listen to their input. Here are some ideas.
+page.image=/distribute/images/know-your-user.jpg
+page.tags="users, growth, global"
+
+@jd:body
+
+<div style="width:100%">
+  <img src="{@docRoot}images/gp-androidify.png">
+</div>
+
+<p>
+  A key part of growing your apps' installed base is knowing more about your
+  users &mdash; how they discover your app, what devices they use, what they do
+  when they use your app, and how often they return to it.
+</p>
+
+<div class="headerLine">
+  <h1 id="read-ratings-comments">
+  Read Ratings Comments
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  The most obvious way to get to know your users is by reading review comments
+  for your apps on Google Play. While the details provided in reviews will vary
+  greatly, in addition to telling you about what users like and dislike in your
+  apps, they can also provide insight into your users’ motivations for using
+  your apps. And remember that users can update their ratings and comments
+  about an app when you fix issues.
+</p>
+
+<p>
+  Learn more about <a href=
+  "{@docRoot}distribute/essentials/optimizing-your-app.html#listen-to-your-users">
+  how to listen to users</a>.
+</p>
+
+<div>
+  <img src="{@docRoot}images/gp-your-user-0.jpg" class="border-img">
+  <p class="img-caption">
+  User ratings
+  </p>
+</div>
+
+<div class="headerLine">
+  <h1 id="start-community">
+  Start a Community
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  Another great way to get to know your users, learn who they are, and what
+  they are looking for, is to start a community. There are many support tools
+  you can use, from forums such as <a href="http://groups.google.com/">Google
+  Groups</a> to comprehensive customer support products. You can integrate some
+  directly into your apps. And once you deploy a support tool, make sure to
+  fill in the support link in your Google Play product details page.
+</p>
+
+<p>
+  <a href="{@docRoot}distribute/users/build-community.html">Learn more about
+  starting and managing a community</a>.
+</p>
+
+<div class="headerLine">
+  <h1 id="create-survey">
+  Create a Survey
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  Consider using a survey to gather information about your users and their
+  views on your apps. Compared to app reviews, a questionnaire enables you to
+  seek specific information. However use with care, as the creation of suitable
+  question is something of an art. Also consider providing an appropriate
+  incentive for completing the questionnaire, as too few responses can be worse
+  than no responses at all.
+</p>
+
+<p>
+  You can create a questionnaire with <a href=
+  "http://www.google.com/drive/apps.html#forms">Google Drive Forms</a> or use
+  one of the various third-party survey and questionnaire hosting tools
+  available, such as SurveyMonkey.
+</p>
+
+<div class="headerLine">
+  <h1 id="add-analytics">
+  Add Analytics to your Apps
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  Analytics data can tell you a lot about your users, by exposing their
+  behaviour in your apps. You can use <a href=
+  "http://android-developers.blogspot.com/2013/10/improved-app-insight-by-linking-google.html">
+  Google Analytics by linking it with your Google Play account</a> or use a
+  third-party analytics tool. Analytics tools can help you gather information
+  on app installs, feature popularity, unused features, and more. You can see
+  any usage pattern differences by region, device, time day and other
+  variables.
+</p>
+
+<p>
+  Read more about <a href=
+  "{@docRoot}distribute/essentials/optimizing-your-app.html#measuring-analyzing-responding">
+  measuring behavior</a>.
+</p>
+
+<div>
+  <img src="{@docRoot}images/gp-dc-stats.png" class="border-img">
+</div>
+
+<div class="headerLine">
+  <h1 id="use-google">
+  Use Google+
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  <a href="https://plus.google.com/">Google+</a> is a great way to gather user
+  feedback, announce surveys and contests, and see how users react to new
+  features and functionality. Many developers manage a Google+ page to
+  communicate with their users. It’s also a good way to get feedback from your
+  beta-testing. Some developers have a page for each of their apps. This is
+  especially true for game developers, who post challenges and tournaments.
+  Google+ can also be used to post game walkthroughs and tips.
+</p>
+
+<div>
+  <img src="{@docRoot}images/gp-your-user-2.jpg">
+</div>
+
+<div class="headerLine clearfloat">
+<h1 id="related-resources">Related Resources</h1><hr>
+</div>
+
+<div class="resource-widget resource-flow-layout col-13"
+  data-query="collection:distribute/users/knowyouruser"
+  data-sortOrder="-timestamp"
+  data-cardSizes="6x3"
+  data-maxResults="6"></div>
\ No newline at end of file
diff --git a/docs/html/distribute/users/users_toc.cs b/docs/html/distribute/users/users_toc.cs
new file mode 100644
index 0000000..a2437a6
--- /dev/null
+++ b/docs/html/distribute/users/users_toc.cs
@@ -0,0 +1,40 @@
+<ul id="nav">
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/users/know-your-user.html">
+            <span class="en">Know Your User</span></a>
+    </div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/users/your-listing.html">
+            <span class="en">Create a Great Listing</span>
+          </a>
+    </div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/users/build-buzz.html">
+          <span class="en">Build Buzz</span>
+        </a>
+    </div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/users/build-community.html">
+          <span class="en">Build Community</span>
+        </a>
+    </div>
+  </li>
+  <li class="nav-section">
+    <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/users/expand-to-new-markets.html">
+          <span class="en">Expand to New Markets</span>
+        </a>
+    </div>
+  </li>
+
+</ul>
+
+
+<script type="text/javascript">
+<!--
+    buildToggleLists();
+    changeNavLang(getLangPref());
+//-->
+</script>
diff --git a/docs/html/distribute/users/your-listing.jd b/docs/html/distribute/users/your-listing.jd
new file mode 100644
index 0000000..cc72fff
--- /dev/null
+++ b/docs/html/distribute/users/your-listing.jd
@@ -0,0 +1,191 @@
+page.title=Create a Great Listing
+page.metaDescription=Make your listing page compelling and integrate it into your marketing campaigns.
+page.image=/distribute/images/create-listing.jpg
+page.tags="listing, google play, users, growth"
+
+@jd:body
+
+<p>
+  Your Google Play app listings are a vital part of your app marketing, from
+  organic traffic or visits you generate through marketing and promotion.
+  Potential users will quickly move on from a poor listing, so the importance
+  of having a great one can't be ignored.
+</p>
+
+<div class="headerLine">
+  <h1 id="graphics-imagery">
+    Graphics &amp; Imagery Tips
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  Be sure to supply a variety of high-quality graphic assets to showcase your
+  apps or brand on Google Play search results and your product details pages.
+  These graphic assets are key parts of successful product details pages that
+  attracts and engages users, so consider having a professional produce them
+  for you.
+</p>
+
+<div>
+  <img src="{@docRoot}images/gp-listing-0.jpg" class="border-img">
+</div>
+
+<h3>
+  Icons
+</h3>
+
+<p>
+  For most users, the <a href=
+  "{@docRoot}design/style/iconography.html#launcher">launcher icon</a>
+  (sometimes referred to as the app icon) is the first impression of your app.
+  As higher density screens on both phones and tablets gain popularity, it's
+  important to make sure your launcher icon is crisp and high quality. To do
+  this, make sure you’re including XHDPI (320dpi) and XXHDPI (480dpi) versions
+  of the icon in your apps. Learn more about <a href=
+  "http://android-developers.blogspot.com/2013/07/making-beautiful-android-app-icons.html">
+  Making Beautiful Android App Icons</a> from the <a href=
+  "http://android-developers.blogspot.com/">Android Developers blog</a>.
+</p>
+
+<div>
+  <img src="{@docRoot}images/gp-listing-1.png" class="border-img">
+</div>
+
+<h3>
+  Screenshots and videos
+</h3>
+
+<p>
+  Be sure to showcase how your apps look, their important features, and what
+  makes them different. Showcase any game play, characters, and their
+  personalities. Some developers build special screens to highlight what’s
+  happening in the screenshot, and extra video footage to highlight the brand.
+  Get more details <a href=
+  "{@docRoot}distribute/tools/launch-checklist.html#prepare-graphics">here</a>.
+</p>
+
+<div>
+  <img src="{@docRoot}images/gp-listing-2.jpg">
+</div>
+
+<div class="sidebox-wrapper" style="float:right;">
+  <div class="sidebox">
+    <p>
+      <strong>Tip:</strong> If your app runs on both phones and tablets, be
+      sure to include screenshots from both devices, including both horizontal
+      and portrait aspect ratios.
+    </p>
+  </div>
+</div>
+
+<h3>
+  Featured image
+</h3>
+
+<p>
+  Choosing the right featured image is important, it needs to convey as much
+  about the features of your apps and what makes them special as possible,
+  without being cluttered and confusing. Check out the <a href=
+  "http://android-developers.blogspot.com/">Android Developers blog</a> post
+  for more <a href=
+  "http://android-developers.blogspot.com/2011/10/android-market-featured-image.html">
+  Featured-Image Guidelines</a>.
+</p>
+
+<div class="headerLine clearfloat">
+  <h1 id="localization-tips">
+    Localization Tips
+  </h1>
+
+  <hr>
+</div>
+
+<div class="sidebox-wrapper" style="float:right;">
+  <div class="sidebox">
+    <p>
+      <strong>Tip:</strong> Translate any embedded text, use different imagery
+      or presentation, and match any marketing promotion to the needs of users
+      in other markets. For example: Some eastern markets respond to price
+      points that end in .00 or .05 more than .99.
+    </p>
+  </div>
+</div>
+
+<p>
+  Many developers start in their country of strength, then expand into new
+  markets. To help you market your apps more effectively to a global audience,
+  create <a href=
+  "http://android-developers.blogspot.com/2012/12/localize-your-promotional-graphics-on.html">
+  localized versions of your promotional graphics, screenshots, and videos</a>.
+  When a user visits your product display pages, Google Play will show the
+  localized assets that you’ve provided for that country. Find out more about
+  <a href="{@docRoot}distribute/users/expand-to-new-markets.html">capitalize on
+  the growing international audience</a>.
+</p>
+
+<div style="float:left;">
+  <img src="{@docRoot}images/gp-listing-3.jpg">
+</div>
+
+<div class="headerLine clearfloat">
+  <h1 id="keyword-tips">
+    Keyword Tips
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  Think carefully about the keywords you use for your apps. Think about words
+  that represent the core feature of your apps. Also consider other words that
+  the user might use to search for your app. For example, if you have a Live
+  Wallpaper app, you may want to include the term ‘background’. This way, users
+  who don’t yet know the terminology can find your app.
+</p>
+
+<div class="headerLine">
+  <h1 id="app-indexing">
+    Sign Up for App Indexing
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  App Indexing provides deep links from Google searches to your apps. Get more
+  details and a link to the sign up page <a href=
+  "https://developers.google.com/app-indexing/">here</a>.
+</p>
+
+<div class="center-img">
+  <img src="{@docRoot}images/gp-listing-4.jpg">
+</div>
+
+<div class="headerLine">
+  <h1 id="education-app">
+    Education App Tips
+  </h1>
+
+  <hr>
+</div>
+
+<p>
+  If you’ve an educational app for the K-12 market, include it in Google Play
+  for Education. Google Play for Education can help your innovative educational
+  apps gain visibility with the right audiences, without having to knock on
+  school doors. Learn more about <a href=
+  "{@docRoot}distribute/googleplay/edu/about.html">Google Play for
+  Education</a>.
+</p>
+
+<div class="headerLine">
+<h1 id="related-resources">Related Resources</h1><hr>
+</div>
+
+<div class="resource-widget resource-flow-layout col-13"
+  data-query="collection:distribute/users/createagreatlisting"
+  data-sortOrder="-timestamp"
+  data-cardSizes="6x3"
+  data-maxResults="6"></div>
\ No newline at end of file
diff --git a/docs/html/google/gcm/ccs.jd b/docs/html/google/gcm/ccs.jd
index d2177ca..03addfd 100644
--- a/docs/html/google/gcm/ccs.jd
+++ b/docs/html/google/gcm/ccs.jd
@@ -8,7 +8,7 @@
 <h2>In this document</h2>
 
 <ol class="toc">
-  <li><a href="#usage">How to Use CCS</a>
+  <li><a href="#connecting">Establishing a Connection</a>
     <ol class="toc">
       <li><a href="#auth">Authentication</a></li>
       </ol>
@@ -46,19 +46,20 @@
 <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) 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>The GCM Cloud Connection Server (CCS) is an XMPP endpoint that provides a
+persistent, asynchronous, bidirectional connection to Google servers. The
+connection can be used to send and receive messages between your server and
+your users' GCM-connected devices.</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,
+  <li>Communication is bidirectional&mdash;not only can your server send messages
+to the device, but the device can send messages back to your server.</li>
+  <li>The device can send messages back using the same connection used for receiving,
 thereby improving battery life.</li>
 </ul>
 
@@ -73,22 +74,34 @@
 <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="connecting">Establishing a Connection</h2>
 
-<h2 id="usage">How to Use CCS</h2>
+<p>CCS just uses XMPP as an authenticated transport layer, so you can use most
+XMPP libraries to manage the connection. For an example, see <a href="#smack">
+Java sample using the Smack library</a>.</p>
 
-<p>GCM Cloud Connection Server (CCS) is an XMPP endpoint, running on
-{@code http://gcm.googleapis.com} port 5235.</p>
+<p>The CCS XMPP endpoint runs at {@code gcm.googleapis.com:5235}. When testing
+functionality (with non-production users), you should instead connect to
+{@code gcm-staging.googleapis.com:5236} (note the different port). Testing on
+staging (a smaller environment where the latest CCS builds run) is beneficial
+both for isolating real users from test code, as well as for early detection of
+unexpected behavior changes.</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>The connection has two important requirements:</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>
+<ul>
+  <li>You must initiate a Transport Layer Security (TLS) connection. Note that
+  CCS doesn't currently support the <a href="http://xmpp.org/rfcs/rfc3920.html"
+  class="external-link" target="_android">STARTTLS extension</a>.</li>
+  <li>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>.</li>
+</ul>
 
-<p> You can use most XMPP libraries to interact with CCS.</p>
+<p>If at any point the connection fails, you should immediately reconnect.
+There is no need to back off after a disconnect that happens after
+authentication.</p>
 
 <h3 id="auth">Authentication</h3>
 
@@ -100,11 +113,11 @@
 </pre>
 <h4>Server</h4>
 <pre>&lt;str:features xmlns:str=&quot;http://etherx.jabber.org/streams&quot;&gt;
- &lt;mechanisms xmlns=&quot;urn:ietf:params:xml:ns:xmpp-sasl&quot;&gt;
-   &lt;mechanism&gt;X-OAUTH2&lt;/mechanism&gt;
-   &lt;mechanism&gt;X-GOOGLE-TOKEN&lt;/mechanism&gt;
-   &lt;mechanism&gt;PLAIN&lt;/mechanism&gt;
- &lt;/mechanisms&gt;
+ &lt;mechanisms xmlns=&quot;urn:ietf:params:xml:ns:xmpp-sasl&quot;&gt;
+   &lt;mechanism&gt;X-OAUTH2&lt;/mechanism&gt;
+   &lt;mechanism&gt;X-GOOGLE-TOKEN&lt;/mechanism&gt;
+   &lt;mechanism&gt;PLAIN&lt;/mechanism&gt;
+ &lt;/mechanisms&gt;
 &lt;/str:features&gt;
 </pre>
 
@@ -118,16 +131,18 @@
 <pre>&lt;success xmlns=&quot;urn:ietf:params:xml:ns:xmpp-sasl&quot;/&gt;</pre>
 
 <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>
+<p>Once the XMPP connection is established, CCS and your server use normal XMPP
+<code>&lt;message&gt;</code> stanzas to send JSON-encoded messages back and
+forth. The body of the <code>&lt;message&gt;</code> must be:</p>
 <pre>
 &lt;gcm xmlns:google:mobile:data&gt;
     <em>JSON payload</em>
 &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 regular GCM messages is similar to
+<a href="http.html#request">what the GCM http endpoint uses</a>, 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>
@@ -136,14 +151,13 @@
 {@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. The value can be either
-'ack' or 'nack'. For example:
-
-<pre>message_type = ('ack');</pre>
-  </li>
 </ul>
+
+<p>In addition to regular GCM messages, control messages are sent, indicated by
+the {@code message_type} field in the JSON object. The value can be either
+'ack' or 'nack', or 'control' (see formats below). Any GCM message with an
+unknown {@code message_type} can be ignored by your server.</p>
+
 <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,
@@ -251,7 +265,9 @@
 &lt;/message&gt;</pre>
 
 
-<p>The following table lists some of the more common NACK error codes.</p>
+<p>The following table lists NACK error codes. Unless otherwise
+indicated, a NACKed message should not be retried. Unexpected NACK error codes
+should be treated the same as {@code INTERNAL_SERVER_ERROR}.</p>
 
 <p class="table-caption" id="table1">
   <strong>Table 1.</strong> NACK error codes.</p>
@@ -262,8 +278,17 @@
 <th>Description</th>
 </tr>
 <tr>
+<td>{@code BAD_ACK}</td>
+<td>The ACK message is improperly formed.</td>
+</tr>
+<tr>
 <td>{@code BAD_REGISTRATION}</td>
-<td>The device has a registration ID, but it's invalid.</td>
+<td>The device has a registration ID, but it's invalid or expired.</td>
+</tr>
+<tr>
+<td>{@code CONNECTION_DRAINING}</td>
+<td>The message couldn't be processed because the connection is draining. The
+message should be immediately retried over another connection.</td>
 </tr>
 <tr>
 <td>{@code DEVICE_UNREGISTERED}</td>
@@ -274,25 +299,20 @@
 <td>The server encountered an error while trying to process the request.</td>
 </tr>
 <tr>
+<td>{@code INVALID_JSON}</td>
+<td>The JSON message payload was not valid.</td>
+</tr>
+<tr>
+<td>{@code QUOTA_EXCEEDED}</td>
+<td>The rate of messages to a particular registration ID (in other words, to a
+sender/device pair) is too high. If you want to retry the message, try using a slower
+rate.</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>
+<td>CCS is not currently able to process the message. The
+message should be retried over the same connection using exponential backoff
+with an initial delay of 1 second.</td>
 </tr>
 </table>
 
@@ -319,6 +339,28 @@
 &lt;/message&gt;
 </pre>
 
+<h4 id="control">Control messages</h4>
+
+<p>Periodically, CCS needs to close down a connection to perform load balancing. Before it
+closes the connection, CCS sends a {@code CONNECTION_DRAINING} message to indicate that the connection is being drained
+and will be closed soon. "Draining" refers to shutting off the flow of messages coming into a
+connection, but allowing whatever is already in the pipeline to continue. When you receive
+a {@code CONNECTION_DRAINING} message, you should immediately begin sending messages to another CCS
+connection, opening a new connection if necessary. You should, however, keep the original
+connection open and continue receiving messages that may come over the connection (and
+ACKing them)&mdash;CCS will handle initiating a connection close when it is ready.</p>
+
+<p>The {@code CONNECTION_DRAINING} message looks like this:</p>
+<pre>&lt;message&gt;
+  &lt;data:gcm xmlns:data=&quot;google:mobile:data&quot;&gt;
+  {
+    &quot;message_type&quot;:&quot;control&quot;
+    &quot;control_type&quot;:&quot;CONNECTION_DRAINING&quot;
+  }
+  &lt;/data:gcm&gt;
+&lt;/message&gt;</pre>
+
+<p>{@code CONNECTION_DRAINING} is currently the only {@code control_type} supported.</p>
 
 <h2 id="upstream">Upstream Messages</h2>
 
@@ -381,7 +423,7 @@
 
 <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
+message count reaches 100, 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>
 
@@ -395,7 +437,7 @@
 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
+apply to these ACKs. Even if the pending message count reaches 100, the 3rd-party app server
 should continue sending ACKs for messages received from CCS to avoid blocking delivery of new
 upstream messages.</p>
 
@@ -795,7 +837,7 @@
 PASSWORD = "API Key"
 REGISTRATION_ID = "Registration Id of the target device"
 
-unacked_messages_quota = 1000
+unacked_messages_quota = 100
 send_queue = []
 
 # Return a random alphanumerical id
diff --git a/docs/html/google/index.jd b/docs/html/google/index.jd
index b743b66..2e97d62 100644
--- a/docs/html/google/index.jd
+++ b/docs/html/google/index.jd
@@ -125,7 +125,7 @@
 <img src="{@docRoot}images/google/analytics.png" width="40" />
   </div>
     <h4><a class="external-link" 
-href="https://developers.google.com/analytics/devguides/collection/android/v2/"
+href="https://developers.google.com/analytics/devguides/collection/android/v4/"
   >Google Analytics</a></h4>
 
 <p>Measure your success and gain insights into how users engage with your app content
diff --git a/docs/html/google/play-services/index.jd b/docs/html/google/play-services/index.jd
index 26b4ccc..5da0b75 100644
--- a/docs/html/google/play-services/index.jd
+++ b/docs/html/google/play-services/index.jd
@@ -71,7 +71,7 @@
 </li>
 <li><strong>Analytics</strong> - Google Analytics and Tag Manager are now part of Google Play services.
    <ul>
-      <li><a href="http://developers.google.com/analytics/devguides/collection/android/v3/" class="external-link">Getting Started with the Analytics API in Android</a></li>
+      <li><a href="http://developers.google.com/analytics/devguides/collection/android/v4/" class="external-link">Getting Started with the Analytics API in Android</a></li>
       <li><a href="/reference/com/google/android/gms/analytics/package-summary.html">Analytics API reference</a></li>
       <li><a href="http://developers.google.com/tag-manager/android/" class="external-link">Getting Started with the Tag Manager API in Android</a></li>
       <li><a href="/reference/com/google/android/gms/tagmanager/package-summary.html">Tag Manager API reference</a></li>
diff --git a/docs/html/google/play-services/maps.jd b/docs/html/google/play-services/maps.jd
index 68a84614..1fae770b 100644
--- a/docs/html/google/play-services/maps.jd
+++ b/docs/html/google/play-services/maps.jd
@@ -1,4 +1,4 @@
-page.title=Google Maps Android API
+page.title=Google Maps Android API v2
 page.tags="mapview","location"
 header.hide=1
 
@@ -12,14 +12,14 @@
 </div>
 <div class="col-6">
 
-  <h1 itemprop="name" style="margin-bottom:0;">Google Maps Android API</h1>
+  <h1 itemprop="name" style="margin-bottom:0;">Google Maps Android API v2</h1>
   <p itemprop="description">Allow your users explore the world with rich maps provided by
   Google. Identify locations with <b>custom markers</b>, augment the map data
   with <b>image overlays</b>, embed <b>one or more maps</b> as fragments,
   and much more.</p>
   <p>Explore the <a
 href="{@docRoot}reference/com/google/android/gms/maps/package-summary.html"
->Google Maps Android API reference</a> or visit <a class="external-link"
+>Google Maps Android API v2 reference</a> or visit <a class="external-link"
 href="https://developers.google.com/maps/documentation/android/">developers.google.com/maps</a>
 for more information about adding maps to your app.</p>
 </div>
@@ -31,7 +31,7 @@
   <div class="col-6 normal-links">
     <h3 style="clear:left">Key Developer Features</h3>
     <h4>Add maps to your app</h4>
-    <p>With version 2 of the Google Maps Android API, you can embed maps into an activity
+    <p>With Google Maps Android API v2, you can embed maps into an activity
     as a fragment with a simple XML snippet. The new Maps offer exciting features such as 3D maps;
     indoor, satellite, terrain, and hybrid maps;
     vector-based tiles for efficient caching and drawing; animated transitions; and much more.
@@ -58,7 +58,7 @@
   <div class="col-6 normal-links">
     <h3 style="clear:left">Getting Started</h3>
     <h4>1. Get the Google Play services SDK</h4>
-    <p>The Google Maps Android APIs are part of the Google Play services platform.</p>
+    <p>Google Maps Android API v2 is part of the Google Play services platform.</p>
     <p>To use Google Maps, <a href="{@docRoot}google/play-services/setup.html">set up
       the Google Play services SDK</a>. Then see the <a class="external-link"
       href="https://developers.google.com/maps/documentation/android/start#installing_the_google_maps_android_v2_api">
@@ -69,7 +69,7 @@
     
     <p>Once you've installed the Google Play services package, the Google Maps sample is located in
       <code>&lt;android-sdk&gt;/extras/google-play-services/samples/maps</code> and shows you
-      how to use the major components of the Google Maps Android APIs.
+      how to use the major components of Google Maps Android API v2.
     </p>
     
     <h4>3. Read the documentation</h4>
@@ -79,12 +79,12 @@
     
     <p>For quick access while developing your Android apps, the
       <a href="{@docRoot}reference/com/google/android/gms/maps/package-summary.html">Google Maps
-      Android API reference</a> is available here on developer.android.com.</p>
+      Android API v2 reference</a> is available here on developer.android.com.</p>
 
-    <p>Detailed documentation for the Google Maps Android APIs is available with the rest of the
+    <p>Detailed documentation for Google Maps Android API v2 is available with the rest of the
     Google Maps developer documents at <a class="external-link"
     href="https://developers.google.com/maps/documentation/android/">developers.google.com/maps</a>.
     </p>
   </div>
 
-</div>
\ No newline at end of file
+</div>
diff --git a/docs/html/google/play-services/setup.jd b/docs/html/google/play-services/setup.jd
index 3137890..5df2629 100644
--- a/docs/html/google/play-services/setup.jd
+++ b/docs/html/google/play-services/setup.jd
@@ -104,7 +104,7 @@
 
 dependencies {
     compile 'com.android.support:appcompat-v7:+'
-    <strong>compile 'com.google.android.gms:play-services:4.0.30'</strong>
+    <strong>compile 'com.google.android.gms:play-services:4.3.23'</strong>
 }
 </pre>
 <p>Be sure you update this version number each time Google Play services is updated.</p>
@@ -235,4 +235,4 @@
 
 
 <p>To then begin a connection to Google Play services, read <a
-href="{@docRoot}google/auth/api-client.html">Accessing Google Play Services APIs</a>.</p>
\ No newline at end of file
+href="{@docRoot}google/auth/api-client.html">Accessing Google Play Services APIs</a>.</p>
diff --git a/docs/html/google/play/billing/billing_subscriptions.jd b/docs/html/google/play/billing/billing_subscriptions.jd
index aa25092..d0e6dc5 100644
--- a/docs/html/google/play/billing/billing_subscriptions.jd
+++ b/docs/html/google/play/billing/billing_subscriptions.jd
@@ -1,6 +1,10 @@
-page.title=Subscriptions
+page.title=Google Play In-App Subscriptions
 parent.title=In-app Billing
 parent.link=index.html
+page.metaDescription=Subscriptions let you sell content or features in your app with automated, recurring billing.
+page.image=/images/play_dev.jpg
+page.tags="inapp, iap, billing"
+meta.tags="monetization, inappbilling, subscriptions"
 @jd:body
 
 <div id="qv-wrapper">
diff --git a/docs/html/google/play/billing/billing_testing.jd b/docs/html/google/play/billing/billing_testing.jd
index 9d1964a..df6c657 100644
--- a/docs/html/google/play/billing/billing_testing.jd
+++ b/docs/html/google/play/billing/billing_testing.jd
@@ -367,6 +367,6 @@
 publish your application on Google Play. You can follow the normal steps for <a
 href="{@docRoot}tools/publishing/preparing.html">preparing</a>, <a
 href="{@docRoot}tools/publishing/app-signing.html">signing</a>, and <a
-href="{@docRoot}distribute/googleplay/publish/preparing.html">publishing on Google Play</a>.
+href="{@docRoot}distribute/tools/launch-checklist.html">publishing on Google Play</a>.
 </p>
 
diff --git a/docs/html/google/play/billing/index.jd b/docs/html/google/play/billing/index.jd
index 481a79c..dce20cb 100644
--- a/docs/html/google/play/billing/index.jd
+++ b/docs/html/google/play/billing/index.jd
@@ -1,4 +1,8 @@
 page.title=Google Play In-app Billing
+page.metaDescription=In-app Billing lets you sell digital content as one-time purchases or subscriptions.
+page.image=/images/play_dev.jpg
+meta.tags="monetizing, inappbilling, subscriptions"
+page.tags="inapp, iap, subscriptions"
 @jd:body
 
 <p>In-app Billing is a Google Play service that lets you sell digital content from inside
@@ -40,8 +44,6 @@
 
 <p>To get started, read the documents below or take the <a href="{@docRoot}training/in-app-billing/index.html">Selling 
     In-app Products</a> training class.</p>
-</div>
-</div>
 
 <dl>
   <dt><strong><a href="{@docRoot}google/play/billing/billing_overview.html">Overview</a></strong></dt>
diff --git a/docs/html/google/play/billing/v2/billing_subscriptions.jd b/docs/html/google/play/billing/v2/billing_subscriptions.jd
index 9c86e20..f8051a9 100644
--- a/docs/html/google/play/billing/v2/billing_subscriptions.jd
+++ b/docs/html/google/play/billing/v2/billing_subscriptions.jd
@@ -382,7 +382,7 @@
 startActivity(intent);</pre>
 
 <p>For more information, see 
-  <a href="{@docRoot}distribute/googleplay/promote/linking.html">Linking to Your Products</a>.</p>
+  <a href="{@docRoot}distribute/tools/promote/linking.html">Linking to Your Products</a>.</p>
 
 <h2 id="purchase-state-changes">Recurring Billing, Cancellation, and Changes In Purchase State</h2>
 
diff --git a/docs/html/google/play/expansion-files.jd b/docs/html/google/play/expansion-files.jd
index a21fbc5..e90f8fa 100644
--- a/docs/html/google/play/expansion-files.jd
+++ b/docs/html/google/play/expansion-files.jd
@@ -1,4 +1,6 @@
 page.title=APK Expansion Files
+page.metaDescription=If your app needs more than the 50MB APK max, use free APK expansion files from Google Play.
+page.tags="apk size, apk max, large assets"
 @jd:body
 
 
diff --git a/docs/html/google/play/licensing/adding-licensing.jd b/docs/html/google/play/licensing/adding-licensing.jd
index 93561f6..3bf4c1a 100644
--- a/docs/html/google/play/licensing/adding-licensing.jd
+++ b/docs/html/google/play/licensing/adding-licensing.jd
@@ -646,7 +646,7 @@
 deep-links the user to the application's details page on Google Play, from which the
 use can purchase the application. For more information on how to set up such
 links, see <a
-href="{@docRoot}distribute/googleplay/promote/linking.html">Linking to Your Products</a>. </li>
+href="{@docRoot}distribute/tools/promote/linking.html">Linking to Your Products</a>. </li>
 <li>Display a Toast notification that indicates that the features of the
 application are limited because it is not licensed. </li>
 </ul>
@@ -988,7 +988,7 @@
 publish the application on Google Play. Follow the normal steps to <a
 href="{@docRoot}tools/publishing/preparing.html">prepare</a>, <a
 href="{@docRoot}tools/publishing/app-signing.html">sign</a>, and then <a
-href="{@docRoot}distribute/googleplay/publish/preparing.html">publish the application</a>.
+href="{@docRoot}distribute/tools/launch-checklist.html">publish the application</a>.
 </p>
 
 
diff --git a/docs/html/google/play/licensing/index.jd b/docs/html/google/play/licensing/index.jd
index 6632fc0..a7ae57a 100644
--- a/docs/html/google/play/licensing/index.jd
+++ b/docs/html/google/play/licensing/index.jd
@@ -1,4 +1,7 @@
-page.title=Application Licensing
+page.title=App Licensing
+page.metaDescription=Information on using the licensing feature of Google Play to protect your apps.
+meta.tags="licensing, drm"
+page.image=/assets/images/resource-card-default-android.jpg
 @jd:body
 
 
diff --git a/docs/html/google/play/licensing/setting-up.jd b/docs/html/google/play/licensing/setting-up.jd
index d83f91b..f43e4aba 100644
--- a/docs/html/google/play/licensing/setting-up.jd
+++ b/docs/html/google/play/licensing/setting-up.jd
@@ -42,7 +42,7 @@
 using your Google account and agree to the Google Play terms of service.</p>
 
 <p>For more information, see <a
-href="{@docRoot}distribute/googleplay/publish/register.html">Get Started with Publishing</a>.</p>
+href="{@docRoot}distribute/googleplay/start.html">Get Started with Publishing</a>.</p>
 
 <p>If you already have a publisher account on Google Play, use your
 Developer Console to set up licensing.</p>
diff --git a/docs/html/guide/components/index.jd b/docs/html/guide/components/index.jd
index 37fb7e9..811d015 100644
--- a/docs/html/guide/components/index.jd
+++ b/docs/html/guide/components/index.jd
@@ -1,7 +1,9 @@
 page.title=App Components
 page.landing=true
 page.landing.intro=Android's application framework lets you create rich and innovative apps using a set of reusable components. This section explains how you can build the components that define the building blocks of your app and how to connect them together using intents. 
+page.metaDescription=Android's application framework lets you create rich and innovative apps using a set of reusable components. This section explains how you can build the components that define the building blocks of your app and how to connect them together using intents. 
 page.landing.image=images/develop/app_components.png
+page.image=images/develop/app_components.png
 
 @jd:body
 
diff --git a/docs/html/guide/components/intents-common.jd b/docs/html/guide/components/intents-common.jd
index 506cf9d..b4813a5 100644
--- a/docs/html/guide/components/intents-common.jd
+++ b/docs/html/guide/components/intents-common.jd
@@ -11,6 +11,18 @@
         <span class="less" style="display:none">show less</span></a></h2>
 
 <ol id="tocIntents" class="hide-nested">
+  <li><a href="#Clock">Alarm Clock</a>
+    <ol>
+      <li><a href="#CreateAlarm">Create an alarm</a></li>
+      <li><a href="#CreateTimer">Create a timer</a></li>
+      <li><a href="#ShowAlarms">Show all alarms</a></li>
+    </ol>
+  </li>
+  <li><a href="#Calendar">Calendar</a>
+    <ol>
+      <li><a href="#AddEvent">Add a calendar event</a></li>
+    </ol>
+  </li>
   <li><a href="#Camera">Camera</a>
     <ol>
       <li><a href="#ImageCapture">Capture a picture or video and return it</a></li>
@@ -44,6 +56,7 @@
   <li><a href="#Music">Music or Video</a>
     <ol>
       <li><a href="#PlayMedia">Play a media file</a></li>
+      <li><a href="#PlaySearch">Play music based on a search query</a></li>
     </ol>
   </li>
   <li><a href="#Phone">Phone</a>
@@ -116,6 +129,292 @@
 
 
 
+
+
+
+
+<h2 id="Clock">Alarm Clock</h2>
+
+
+<h3 id="CreateAlarm">Create an alarm</h3>
+
+<p>To create a new alarm, use the {@link android.provider.AlarmClock#ACTION_SET_ALARM}
+action and specify alarm details such as the time and message using extras defined below.</p>
+
+<p class="note"><strong>Note:</strong> Only the hour, minutes, and message extras are available
+since Android 2.3 (API level 9). The other extras were added in later versions of the platform.</p>
+
+<dl>
+<dt><b>Action</b></dt>
+<dd>{@link android.provider.AlarmClock#ACTION_SET_ALARM}</dd>
+
+<dt><b>Data URI</b></dt>
+<dd>None</dd>
+
+<dt><b>MIME Type</b></dt>
+<dd>None
+</dd>
+
+<dt><b>Extras</b></dt>
+<dd>
+  <dl>
+    <dt>{@link android.provider.AlarmClock#EXTRA_HOUR}</dt>
+      <dd>The hour for the alarm.</dd>
+    <dt>{@link android.provider.AlarmClock#EXTRA_MINUTES}</dt>
+      <dd>The minutes for the alarm.</dd>
+    <dt>{@link android.provider.AlarmClock#EXTRA_MESSAGE}</dt>
+      <dd>A custom message to identify the alarm.</dd>
+    <dt>{@link android.provider.AlarmClock#EXTRA_DAYS}</dt>
+      <dd>An {@link java.util.ArrayList} including each week day on which this alarm should
+      be repeated. Each day must be declared with an integer from the {@link java.util.Calendar}
+      class such as {@link java.util.Calendar#MONDAY}.
+      <p>For a one-time alarm, do not specify this extra.</dd>
+    <dt>{@link android.provider.AlarmClock#EXTRA_RINGTONE}</dt>
+      <dd>A {@code content:} URI specifying a ringtone to use with the alarm, or {@link
+      android.provider.AlarmClock#VALUE_RINGTONE_SILENT} for no ringtone.
+      <p>To use the default ringtone, do not specify this extra.</dd>
+    <dt>{@link android.provider.AlarmClock#EXTRA_VIBRATE}</dt>
+      <dd>A boolean specifying whether to vibrate for this alarm.</dd>
+    <dt>{@link android.provider.AlarmClock#EXTRA_SKIP_UI}</dt>
+      <dd>A boolean specifying whether the responding app should skip its UI when setting the alarm.
+      If true, the app should bypass any confirmation UI and simply set the specified alarm.</dd>
+  </dl>
+</dd>
+
+
+</dl>
+
+<p><b>Example intent:</b></p>
+<pre>
+public void createAlarm(String message, int hour, int minutes) {
+    Intent intent = new Intent(AlarmClock.ACTION_SET_ALARM)
+            .putExtra(AlarmClock.EXTRA_MESSAGE, message)
+            .putExtra(AlarmClock.EXTRA_HOUR, hour)
+            .putExtra(AlarmClock.EXTRA_MINUTES, minutes);
+    if (intent.resolveActivity(getPackageManager()) != null) {
+        startActivity(intent);
+    }
+}
+</pre>
+
+<div class="note"><strong>Note:</strong>
+<p>In order to invoke the {@link
+android.provider.AlarmClock#ACTION_SET_ALARM} intent, your app must have the
+{@link android.Manifest.permission#SET_ALARM} permission:</p>
+<pre>
+&lt;uses-permission android:name="com.android.alarm.permission.SET_ALARM" />
+</pre>
+</div>
+
+
+<p><b>Example intent filter:</b></p>
+<pre>
+&lt;activity ...>
+    &lt;intent-filter>
+        &lt;action android:name="android.intent.action.SET_ALARM" />
+        &lt;category android:name="android.intent.category.DEFAULT" />
+    &lt;/intent-filter>
+&lt;/activity>
+</pre>
+
+
+
+<h3 id="CreateTimer">Create a timer</h3>
+
+<p>To create a countdown timer, use the {@link android.provider.AlarmClock#ACTION_SET_TIMER}
+action and specify timer details such as the duration using extras defined below.</p>
+
+<p class="note"><strong>Note:</strong> This intent was added
+in Android 4.4 (API level 19).</p>
+
+<dl>
+<dt><b>Action</b></dt>
+<dd>{@link android.provider.AlarmClock#ACTION_SET_TIMER}</dd>
+
+<dt><b>Data URI</b></dt>
+<dd>None</dd>
+
+<dt><b>MIME Type</b></dt>
+<dd>None
+</dd>
+
+<dt><b>Extras</b></dt>
+<dd>
+  <dl>
+    <dt>{@link android.provider.AlarmClock#EXTRA_LENGTH}</dt>
+      <dd>The length of the timer in seconds.</dd>
+    <dt>{@link android.provider.AlarmClock#EXTRA_MESSAGE}</dt>
+      <dd>A custom message to identify the timer.</dd>
+    <dt>{@link android.provider.AlarmClock#EXTRA_SKIP_UI}</dt>
+      <dd>A boolean specifying whether the responding app should skip its UI when setting the timer.
+      If true, the app should bypass any confirmation UI and simply start the specified timer.</dd>
+  </dl>
+</dd>
+
+
+</dl>
+
+<p><b>Example intent:</b></p>
+<pre>
+public void startTimer(String message, int seconds) {
+    Intent intent = new Intent(AlarmClock.ACTION_SET_TIMER)
+            .putExtra(AlarmClock.EXTRA_MESSAGE, message)
+            .putExtra(AlarmClock.EXTRA_LENGTH, seconds)
+            .putExtra(AlarmClock.EXTRA_SKIP_UI, true);
+    if (intent.resolveActivity(getPackageManager()) != null) {
+        startActivity(intent);
+    }
+}
+</pre>
+
+<div class="note"><strong>Note:</strong>
+<p>In order to invoke the {@link
+android.provider.AlarmClock#ACTION_SET_TIMER} intent, your app must have the
+{@link android.Manifest.permission#SET_ALARM} permission:</p>
+<pre>
+&lt;uses-permission android:name="com.android.alarm.permission.SET_ALARM" />
+</pre>
+</div>
+
+
+<p><b>Example intent filter:</b></p>
+<pre>
+&lt;activity ...>
+    &lt;intent-filter>
+        &lt;action android:name="android.intent.action.SET_TIMER" />
+        &lt;category android:name="android.intent.category.DEFAULT" />
+    &lt;/intent-filter>
+&lt;/activity>
+</pre>
+
+
+
+
+
+<h3 id="ShowAlarms">Show all alarms</h3>
+
+<p>To show the list of alarms, use the {@link android.provider.AlarmClock#ACTION_SHOW_ALARMS}
+action.</p>
+
+<p>Although not many apps will invoke this intent (it's primarily used by system apps),
+any app that behaves as an alarm clock should implement
+this intent filter and respond by showing the list of current alarms.</p>
+
+<p class="note"><strong>Note:</strong> This intent was added
+in Android 4.4 (API level 19).</p>
+
+<dl>
+<dt><b>Action</b></dt>
+<dd>{@link android.provider.AlarmClock#ACTION_SHOW_ALARMS}</dd>
+
+<dt><b>Data URI</b></dt>
+<dd>None</dd>
+
+<dt><b>MIME Type</b></dt>
+<dd>None
+</dd>
+</dl>
+
+<p><b>Example intent filter:</b></p>
+<pre>
+&lt;activity ...>
+    &lt;intent-filter>
+        &lt;action android:name="android.intent.action.SHOW_ALARMS" />
+        &lt;category android:name="android.intent.category.DEFAULT" />
+    &lt;/intent-filter>
+&lt;/activity>
+</pre>
+
+
+
+
+
+
+<h2 id="Calendar">Calendar</h2>
+
+
+<h3 id="AddEvent">Add a calendar event</h3>
+
+<p>To add a new event to the user's calendar, use the {@link android.content.Intent#ACTION_INSERT}
+action and specify the data URI with {@link android.provider.CalendarContract.Events#CONTENT_URI
+Events.CONTENT_URI}. You can then specify various event details using extras defined below.</p>
+
+<dl>
+<dt><b>Action</b></dt>
+<dd>{@link android.content.Intent#ACTION_INSERT}</dd>
+
+<dt><b>Data URI</b></dt>
+<dd>{@link android.provider.CalendarContract.Events#CONTENT_URI
+Events.CONTENT_URI}</dd>
+
+<dt><b>MIME Type</b></dt>
+<dd>{@code "vnd.android.cursor.dir/event"}
+</dd>
+
+<dt><b>Extras</b></dt>
+<dd>
+  <dl>
+    <dt>{@link android.provider.CalendarContract#EXTRA_EVENT_ALL_DAY}</dt>
+      <dd>A boolean specifying whether this is an all-day event.</dd>
+    <dt>{@link android.provider.CalendarContract#EXTRA_EVENT_BEGIN_TIME}</dt>
+      <dd>The start time of the event (milliseconds since epoch).</dd>
+    <dt>{@link android.provider.CalendarContract#EXTRA_EVENT_END_TIME}</dt>
+      <dd>The end time of the event (milliseconds since epoch).</dd>
+    <dt>{@link android.provider.CalendarContract.EventsColumns#TITLE}</dt>
+      <dd>The event title.</dd>
+    <dt>{@link android.provider.CalendarContract.EventsColumns#DESCRIPTION}</dt>
+      <dd>The event description.</dd>
+    <dt>{@link android.provider.CalendarContract.EventsColumns#EVENT_LOCATION}</dt>
+      <dd>The event location.</dd>
+    <dt>{@link android.content.Intent#EXTRA_EMAIL}</dt>
+      <dd>A comma-separated list of email addresses that specify the invitees.</dd>
+  </dl>
+  <p>Many more event details can be specified using the constants defined in the
+  {@link android.provider.CalendarContract.EventsColumns} class.</p>
+</dd>
+
+
+</dl>
+
+<p><b>Example intent:</b></p>
+<pre>
+public void addEvent(String title, String location, Calendar begin, Calendar end) {
+    Intent intent = new Intent(Intent.ACTION_INSERT)
+            .setData(Events.CONTENT_URI)
+            .putExtra(Events.TITLE, title)
+            .putExtra(Events.EVENT_LOCATION, location)
+            .putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, begin)
+            .putExtra(CalendarContract.EXTRA_EVENT_END_TIME, end);
+    if (intent.resolveActivity(getPackageManager()) != null) {
+        startActivity(intent);
+    }
+}
+</pre>
+
+
+<p><b>Example intent filter:</b></p>
+<pre>
+&lt;activity ...>
+    &lt;intent-filter>
+        &lt;action android:name="android.intent.action.INSERT" />
+        &lt;data android:mimeType="vnd.android.cursor.dir/event" />
+        &lt;category android:name="android.intent.category.DEFAULT" />
+    &lt;/intent-filter>
+&lt;/activity>
+</pre>
+
+
+
+
+
+
+
+
+
+
+
+
+
 <h2 id="Camera">Camera</h2>
 
 
@@ -211,6 +510,7 @@
 
 
 
+
 <h2 id="Contacts">Contacts/People App</h2>
 
 
@@ -427,7 +727,7 @@
 <dd>The type is inferred from contact URI.
 </dd>
 
-<dt><b>Extras</b> (optional)</dt>
+<dt><b>Extras</b></dt>
 <dd>One or more of the extras defined in {@link android.provider.ContactsContract.Intents.Insert}
 so you can populate fields of the contact details.
 </dd>
@@ -437,7 +737,7 @@
 <pre>
 public void editContact(Uri contactUri, String email) {
     Intent intent = new Intent(Intent.ACTION_EDIT);
-    intent.setDataAndType(contactUri, Contacts.CONTENT_TYPE);
+    intent.setData(contactUri);
     intent.putExtra(Intents.Insert.EMAIL, email);
     if (intent.resolveActivity(getPackageManager()) != null) {
         startActivity(intent);
@@ -469,7 +769,7 @@
 <dt><b>MIME Type</b></dt>
 <dd>{@link android.provider.ContactsContract.Contacts#CONTENT_TYPE Contacts.CONTENT_TYPE}</dd>
 
-<dt><b>Extras</b> (optional)</dt>
+<dt><b>Extras</b></dt>
 <dd>One or more of the extras defined in {@link android.provider.ContactsContract.Intents.Insert}.
 </dd>
 </dl>
@@ -523,7 +823,7 @@
   </dl>
 </dd>
 
-<dt><b>Extras</b> (optional)</dt>
+<dt><b>Extras</b></dt>
 <dd>
   <dl>
     <dt>{@link android.content.Intent#EXTRA_EMAIL Intent.EXTRA_EMAIL}</dt>
@@ -648,7 +948,7 @@
 <dd>The MIME type corresponding to the file type the user should select.
 </dd>
 
-<dt><b>Extras</b> (optional)</dt>
+<dt><b>Extras</b></dt>
 <dd>
   <dl>
     <dt>{@link android.content.Intent#EXTRA_ALLOW_MULTIPLE}
@@ -768,7 +1068,7 @@
 <dd>The MIME type corresponding to the file type the user should select.
 </dd>
 
-<dt><b>Extras</b> (optional)</dt>
+<dt><b>Extras</b></dt>
 <dd>
   <dl>
     <dt>{@link android.content.Intent#EXTRA_MIME_TYPES}
@@ -988,9 +1288,251 @@
 </pre>
 
 
+<h3 id="PlaySearch">Play music based on a search query</h3>
+
+<p>To play music based on a search query, use the
+{@link android.provider.MediaStore#INTENT_ACTION_MEDIA_PLAY_FROM_SEARCH} intent. An app may fire
+this intent in response to the user's voice command to play music. The receiving app for this
+intent performs a search within its inventory to match existing content to the given query and
+starts playing that content.</p>
+
+<p>This intent should include the {@link android.provider.MediaStore#EXTRA_MEDIA_FOCUS} string
+extra, which specifies the inteded search mode. For example, the search mode can specify whether
+the search is for an artist name or song name.</p>
+
+<dl>
+<dt><b>Action</b></dt>
+<dd>{@link android.provider.MediaStore#INTENT_ACTION_MEDIA_PLAY_FROM_SEARCH}</dd>
+
+<dt><b>Data URI Scheme</b></dt>
+<dd>None</dd>
+
+<dt><b>MIME Type</b></dt>
+<dd>None</dd>
+
+<dt><b>Extras</b></dt>
+<dd>
+<dl>
+<dt>{@link android.provider.MediaStore#EXTRA_MEDIA_FOCUS MediaStore.EXTRA_MEDIA_FOCUS} (required)</dt>
+<dd>
+<p>Indicates the search mode (whether the user is looking for a particular artist, album, song,
+playlist, or radio channel). Most search modes take additional extras. For example, if the user
+is interested in listening to a particular song, the intent might have three additional extras:
+the song title, the artist, and the album. This intent supports the following search modes for
+each value of {@link android.provider.MediaStore#EXTRA_MEDIA_FOCUS}:</p>
+<dl>
+<dt><p><em>Any</em> - <code>"vnd.android.cursor.item/*"</p></code></dt>
+<dd>
+<p>Play any music. The receiving app should play some music based on a smart choice, such
+as the last playlist the user listened to.</p>
+<p>Additional extras:</p>
+<ul>
+  <li>{@link android.app.SearchManager#QUERY} (required) - An empty string. This extra is always
+      provided for backward compatibility: existing apps that do not know about search modes can
+      process this intent as an unstructured search.</li>
+</ul>
+</dd>
+<dt><p><em>Unstructured</em> - <code>"vnd.android.cursor.item/*"</code></p></dt>
+<dd>
+<p>Play a particular song, album or genre from an unstructured search query. Apps may generate
+an intent with this search mode when they can't identify the type of content the user wants to
+listen to. Apps should use more specific search modes when possible.</p>
+<p>Additional extras:</p>
+<ul>
+  <li>{@link android.app.SearchManager#QUERY} (required) - A string that contains any combination
+      of: the artist, the album, the song name, or the genre.</li>
+</ul>
+</dd>
+<dt><p><em>Genre</em> -
+{@link android.provider.MediaStore.Audio.Genres#ENTRY_CONTENT_TYPE Audio.Genres.ENTRY_CONTENT_TYPE}</p></dt>
+<dd>
+<p>Play music of a particular genre.</p>
+<p>Additional extras:</p>
+<ul>
+  <li><code>"android.intent.extra.genre"</code> (required) - The genre.</li>
+  <li>{@link android.app.SearchManager#QUERY} (required) - The genre. This extra is always provided
+      for backward compatibility: existing apps that do not know about search modes can process
+      this intent as an unstructured search.</li>
+</ul>
+</dd>
+<dt><p><em>Artist</em> -
+{@link android.provider.MediaStore.Audio.Artists#ENTRY_CONTENT_TYPE Audio.Artists.ENTRY_CONTENT_TYPE}</p></dt>
+<dd>
+<p>Play music from a particular artist.</p>
+<p>Additional extras:</p>
+<ul>
+  <li>{@link android.provider.MediaStore#EXTRA_MEDIA_ARTIST} (required) - The artist.</li>
+  <li><code>"android.intent.extra.genre"</code> - The genre.</li>
+  <li>{@link android.app.SearchManager#QUERY} (required) - A string that contains any combination of
+      the artist or the genre. This extra is always provided for backward compatibility:
+      existing apps that do not know about search modes can process this intent as an unstructured
+      search.</li>
+</ul>
+</dd>
+<dt><p><em>Album</em> -
+{@link android.provider.MediaStore.Audio.Albums#ENTRY_CONTENT_TYPE Audio.Albums.ENTRY_CONTENT_TYPE}</p></dt>
+<dd>
+<p>Play music from a particular album.</p>
+<p>Additional extras:</p>
+<ul>
+  <li>{@link android.provider.MediaStore#EXTRA_MEDIA_ALBUM} (required) - The album.</li>
+  <li>{@link android.provider.MediaStore#EXTRA_MEDIA_ARTIST} - The artist.</li>
+  <li><code>"android.intent.extra.genre"</code> - The genre.</li>
+  <li>{@link android.app.SearchManager#QUERY} (required) - A string that contains any combination of
+      the album or the artist. This extra is always provided for backward
+      compatibility: existing apps that do not know about search modes can process this intent as an
+      unstructured search.</li>
+</ul>
+</dd>
+<dt><p><em>Song</em> - <code>"vnd.android.cursor.item/audio"</code></p></dt>
+<dd>
+<p>Play a particular song.</p>
+<p>Additional extras:</p>
+<ul>
+  <li>{@link android.provider.MediaStore#EXTRA_MEDIA_ALBUM} - The album.</li>
+  <li>{@link android.provider.MediaStore#EXTRA_MEDIA_ARTIST} - The artist.</li>
+  <li><code>"android.intent.extra.genre"</code> - The genre.</li>
+  <li>{@link android.provider.MediaStore#EXTRA_MEDIA_TITLE} (required) - The song name.</li>
+  <li>{@link android.app.SearchManager#QUERY} (required) - A string that contains any combination of:
+      the album, the artist, the genre, or the title. This extra is always provided for
+      backward compatibility: existing apps that do not know about search modes can process this
+      intent as an unstructured search.</li>
+</ul>
+</dd>
+<dt><p><em>Radio channel</em> - <code>"vnd.android.cursor.item/radio"</code></p></dt>
+<dd>
+<p>Play a particular radio channel or a radio channel that matches some criteria specified
+by additional extras.</p>
+<p>Additional extras:</p>
+<ul>
+  <li>{@link android.provider.MediaStore#EXTRA_MEDIA_ALBUM} - The album.</li>
+  <li>{@link android.provider.MediaStore#EXTRA_MEDIA_ARTIST} - The artist.</li>
+  <li><code>"android.intent.extra.genre"</code> - The genre.</li>
+  <li><code>"android.intent.extra.radio_channel"</code> - The radio channel.</li>
+  <li>{@link android.provider.MediaStore#EXTRA_MEDIA_TITLE} - The song name that the radio
+      channel is based on.</li>
+  <li>{@link android.app.SearchManager#QUERY} (required) - A string that contains any combination
+      of: the album, the artist, the genre, the radio channel, or the title. This extra is
+      always provided for backward compatibility: existing apps that do not know about search
+      modes can process this intent as an unstructured search.</li>
+</ul>
+</dd>
+<dt><p><em>Playlist</em> - {@link android.provider.MediaStore.Audio.Playlists#ENTRY_CONTENT_TYPE Audio.Playlists.ENTRY_CONTENT_TYPE}</p></dt>
+<dd>
+<p>Play a particular playlist or a playlist that matches some criteria specified
+by additional extras.</p>
+<p>Additional extras:</p>
+<ul>
+  <li>{@link android.provider.MediaStore#EXTRA_MEDIA_ALBUM} - The album.</li>
+  <li>{@link android.provider.MediaStore#EXTRA_MEDIA_ARTIST} - The artist.</li>
+  <li><code>"android.intent.extra.genre"</code> - The genre.</li>
+  <li><code>"android.intent.extra.playlist"</code> - The playlist.</li>
+  <li>{@link android.provider.MediaStore#EXTRA_MEDIA_TITLE} - The song name that the playlist is
+      based on.</li>
+  <li>{@link android.app.SearchManager#QUERY} (required) - A string that contains any combination
+      of: the album, the artist, the genre, the playlist, or the title. This extra is always
+      provided for backward compatibility: existing apps that do not know about search modes can
+      process this intent as an unstructured search.</li>
+</ul>
+</dd>
+</dl>
+</dd>
+</dl>
+</dd>
+</dl>
 
 
 
+<p><b>Example intent:</b></p>
+<p>If the user wants to listen to a radio station that plays songs from a particular artist,
+a search app may generate the following intent:</p>
+<pre>
+public void playSearchRadioByArtist(String artist) {
+    Intent intent = new Intent(MediaStore.INTENT_ACTION_MEDIA_PLAY_FROM_SEARCH);
+    intent.putExtra(MediaStore.EXTRA_MEDIA_FOCUS,
+                    "vnd.android.cursor.item/radio");
+    intent.putExtra(MediaStore.EXTRA_MEDIA_ARTIST, artist);
+    intent.putExtra(SearchManager.QUERY, artist);
+    if (intent.resolveActivity(getPackageManager()) != null) {
+        startActivity(intent);
+    }
+}
+</pre>
+
+<p><b>Example intent filter:</b></p>
+<pre>
+&lt;activity ...>
+    &lt;intent-filter>
+        &lt;action android:name="android.media.action.MEDIA_PLAY_FROM_SEARCH" />
+        &lt;category android:name="android.intent.category.DEFAULT" />
+    &lt;/intent-filter>
+&lt;/activity>
+</pre>
+<p>When handling this intent, your activity should check the value of the
+{@link android.provider.MediaStore#EXTRA_MEDIA_FOCUS} extra in the incoming
+{@link android.content.Intent} to determine the search mode. Once your activity has identified
+the search mode, it should read the values of the additional extras for that particular search mode.
+With this information your app can then perform the search within its inventory to play the
+content that matches the search query. For example:</p>
+<pre>
+protected void onCreate(Bundle savedInstanceState) {
+    ...
+    Intent intent = this.getIntent();
+    if (intent.getAction().compareTo(MediaStore.INTENT_ACTION_MEDIA_PLAY_FROM_SEARCH) == 0) {
+
+        String mediaFocus = intent.getStringExtra(MediaStore.EXTRA_MEDIA_FOCUS);
+        String query = intent.getStringExtra(SearchManager.QUERY);
+
+        // Some of these extras may not be available depending on the search mode
+        String album = intent.getStringExtra(MediaStore.EXTRA_MEDIA_ALBUM);
+        String artist = intent.getStringExtra(MediaStore.EXTRA_MEDIA_ARTIST);
+        String genre = intent.getStringExtra("android.intent.extra.genre");
+        String playlist = intent.getStringExtra("android.intent.extra.playlist");
+        String rchannel = intent.getStringExtra("android.intent.extra.radio_channel");
+        String title = intent.getStringExtra(MediaStore.EXTRA_MEDIA_TITLE);
+
+        // Determine the search mode and use the corresponding extras
+        if (mediaFocus == null) {
+            // 'Unstructured' search mode (backward compatible)
+            playUnstructuredSearch(query);
+
+        } else if (mediaFocus.compareTo("vnd.android.cursor.item/*") == 0) {
+            if (query.isEmpty()) {
+                // 'Any' search mode
+                playResumeLastPlaylist();
+            } else {
+                // 'Unstructured' search mode
+                playUnstructuredSearch(query);
+            }
+
+        } else if (mediaFocus.compareTo(MediaStore.Audio.Genres.ENTRY_CONTENT_TYPE) == 0) {
+            // 'Genre' search mode
+            playGenre(genre);
+
+        } else if (mediaFocus.compareTo(MediaStore.Audio.Artists.ENTRY_CONTENT_TYPE) == 0) {
+            // 'Artist' search mode
+            playArtist(artist, genre);
+
+        } else if (mediaFocus.compareTo(MediaStore.Audio.Albums.ENTRY_CONTENT_TYPE) == 0) {
+            // 'Album' search mode
+            playAlbum(album, artist);
+
+        } else if (mediaFocus.compareTo("vnd.android.cursor.item/audio") == 0) {
+            // 'Song' search mode
+            playSong(album, artist, genre, title);
+
+        } else if (mediaFocus.compareTo("vnd.android.cursor.item/radio") == 0) {
+            // 'Radio channel' search mode
+            playRadioChannel(album, artist, genre, rchannel, title);
+
+        } else if (mediaFocus.compareTo(MediaStore.Audio.Playlists.ENTRY_CONTENT_TYPE) == 0) {
+            // 'Playlist' search mode
+            playPlaylist(album, artist, genre, playlist, title);
+        }
+    }
+}
+</pre>
+
 
 
 
@@ -1139,7 +1681,7 @@
   </dl>
 </dd>
 
-<dt><b>Extras</b> (optional)</dt>
+<dt><b>Extras</b></dt>
 <dd>
   <dl>
     <dt><code>"subject"</code></dt>
diff --git a/docs/html/guide/guide_toc.cs b/docs/html/guide/guide_toc.cs
index 73d5b74..0a234aa 100644
--- a/docs/html/guide/guide_toc.cs
+++ b/docs/html/guide/guide_toc.cs
@@ -368,7 +368,10 @@
                   <span class="en">Media Playback</span></a>
                 </li>
             <li><a href="<?cs var:toroot ?>guide/topics/media/mediarouter.html">
-                  <span class="en">MediaRouter</span></a>
+                  <span class="en">Media Router</span></a>
+                </li>
+            <li><a href="<?cs var:toroot ?>guide/topics/media/mediarouteprovider.html">
+                  <span class="en">Media Route Provider</span></a>
                 </li>
             <li><a href="<?cs var:toroot ?>guide/appendix/media-formats.html">
                    <span class="en">Supported Media Formats</span></a>
diff --git a/docs/html/guide/practices/screens_support.jd b/docs/html/guide/practices/screens_support.jd
index 8c76411..dbe6c1a 100644
--- a/docs/html/guide/practices/screens_support.jd
+++ b/docs/html/guide/practices/screens_support.jd
@@ -1,4 +1,7 @@
 page.title=Supporting Multiple Screens
+page.metaDescription=Nanaging UIs for the best display on multiple screen sizes.
+meta.tags="multiple screens"
+
 @jd:body
 
 <div id="qv-wrapper">
diff --git a/docs/html/guide/topics/data/backup.jd b/docs/html/guide/topics/data/backup.jd
index 4903852..f09ff9e 100644
--- a/docs/html/guide/topics/data/backup.jd
+++ b/docs/html/guide/topics/data/backup.jd
@@ -899,8 +899,9 @@
 {@code tools/} path:
 <pre class="no-pretty-print">adb shell bmgr enable true</pre>
       </li>
-      <li>If using a device, open the system <b>Settings</b>, select <b>Privacy</b>, then enable
-<b>Back up my data</b> and <b>Automatic restore</b>.
+      <li>If using a device, open the system <b>Settings</b>, select
+      <b>Backup & reset</b>, then enable
+      <b>Back up my data</b> and <b>Automatic restore</b>.</li>
     </ul>
   </li>
   <li>Open your application and initialize some data
diff --git a/docs/html/guide/topics/manifest/manifest-element.jd b/docs/html/guide/topics/manifest/manifest-element.jd
index 20dc4ea..7717696 100644
--- a/docs/html/guide/topics/manifest/manifest-element.jd
+++ b/docs/html/guide/topics/manifest/manifest-element.jd
@@ -30,7 +30,7 @@
 <br/><code><a href="{@docRoot}guide/topics/manifest/permission-element.html">&lt;permission&gt;</a></code>
 <br/><code><a href="{@docRoot}guide/topics/manifest/permission-group-element.html">&lt;permission-group&gt;</a></code>
 <br/><code><a href="{@docRoot}guide/topics/manifest/permission-tree-element.html">&lt;permission-tree&gt;</a></code>
-<br/><code><a href="{@docRoot}guide/topics/manifest/supports-gl-texture.html">&lt;supports-gl-texture&gt;</a></code
+<br/><code><a href="{@docRoot}guide/topics/manifest/supports-gl-texture-element.html">&lt;supports-gl-texture&gt;</a></code>
 <br/><code><a href="{@docRoot}guide/topics/manifest/supports-screens-element.html">&lt;supports-screens&gt;</a></code>
 <br/><code><a href="{@docRoot}guide/topics/manifest/uses-configuration-element.html">&lt;uses-configuration&gt;</a></code>  <!-- ##api level 3## -->
 <br/><code><a href="{@docRoot}guide/topics/manifest/uses-feature-element.html">&lt;uses-feature&gt;</a></code>
@@ -193,4 +193,4 @@
 <dd>
 <code><a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code></dd>
 
-</dl>
\ No newline at end of file
+</dl>
diff --git a/docs/html/guide/topics/manifest/uses-feature-element.jd b/docs/html/guide/topics/manifest/uses-feature-element.jd
index d421591..ca954fe 100644
--- a/docs/html/guide/topics/manifest/uses-feature-element.jd
+++ b/docs/html/guide/topics/manifest/uses-feature-element.jd
@@ -584,9 +584,14 @@
 </tr>
 <tr>
   <td><code>android.hardware.camera.any</code></td>
-  <td>The application uses at least one camera facing in any direction. Use this
-in preference to <code>android.hardware.camera</code> if a back-facing camera is
-not required.</td>
+  <td>The application uses at least one camera facing in any direction, or an
+external camera device if one is connected. Use this in preference to
+<code>android.hardware.camera</code> if a back-facing camera is not required.
+  </td>
+</tr>
+<tr>
+  <td><code>android.hardware.camera.external</code></td>
+  <td>The application uses an external camera device if one is connected.</td>
 </tr>
 
 <tr>
@@ -684,7 +689,7 @@
   <td>The application requires landscape orientation.</td>
   <td rowspan="2">
      <p>For example, if your app requires portrait orientation, you should declare
-<code>&lt;uses-feature android:name="android.hardware.screen.portrait"/></code> so that only devices
+<code>&lt;uses-feature android:name="android.hardware.screen.portrait"/&gt;</code> so that only devices
 that support portrait orientation (whether always or by user choice) can install your app. If your
 application <em>supports</em> both orientations, then you don't need to declare either.</p>
     <p>Both orientations are assumed <em>not required</em>, by default, so your app may be installed
@@ -1099,4 +1104,4 @@
   <td><code>android.hardware.wifi</code></td>
 <!--  <td></td> -->
 </tr>
-</table>
\ No newline at end of file
+</table>
diff --git a/docs/html/guide/topics/media/mediarouteprovider.jd b/docs/html/guide/topics/media/mediarouteprovider.jd
new file mode 100644
index 0000000..389fbfb
--- /dev/null
+++ b/docs/html/guide/topics/media/mediarouteprovider.jd
@@ -0,0 +1,453 @@
+page.title=Media Route Provider
+page.tags="mediarouteprovider","mediacontrolintent"
+@jd:body
+
+<div id="qv-wrapper">
+  <div id="qv">
+    <h2>In this document</h2>
+    <ol>
+      <li><a href="#overview">Overview</a>
+        <ol>
+          <li><a href="#dist">Distribution of route providers</a></li>
+          <li><a href="#playback-types">Types of playback</a></li>
+          <li><a href="#mr-packages">Media router packages</a></li>
+        </ol>
+      </li>
+      <li><a href="#provider-service">Creating a Provider Service</a></li>
+      <li><a href="#route-caps">Specifying Route Capabilities</a>
+        <ol>
+          <li><a href="#route-cat">Route categories</a></li>
+          <li><a href="#media-types">Media types and protocols</a></li>
+          <li><a href="#playback-ctrls">Playback controls</a></li>
+          <li><a href="#mrpd">MediaRouteProviderDescriptor</a></li>
+        </ol>
+      </li>
+      <li><a href="#ctrl-routes">Controlling Routes</a></li>
+    </ol>
+    <h2>Key Classes</h2>
+    <ol>
+      <li>{@link android.support.v7.media.MediaRouteProvider}</li>
+      <li>{@link android.support.v7.media.MediaRouteProviderDescriptor}</li>
+      <li>{@link android.support.v7.media.MediaRouteProvider.RouteController RouteController}</li>
+    </ol>
+    <h2>Related Samples</h2>
+    <ol>
+      <li><a href="{@docRoot}samples/MediaRouter/index.html">MediaRouter</a></li>
+    </ol>
+  </div>
+</div>
+
+<p>Users want to play media content from their Android devices bigger, brighter, and louder on
+  connected playback devices such as televisions, stereos,
+  and home theater equipment. As a manufacturer of these devices, allowing Android users to
+  instantly show a picture, play a song, or share a video for friends and family using your product
+  can make it much more compelling and engaging.</p>
+
+<p>The Android media router framework allows manufacturers to enable playback on their devices
+  through a standardized interface called a {@link android.support.v7.media.MediaRouteProvider}.
+  A route provider defines a common interface for playing media on a receiver device, making it
+  possible to play media on your equipment from any Android application that supports media
+  routes.</p>
+
+<p>This guide discusses how to create a media route provider for a receiver device and make it
+  available to other media playback applications that run on Android.</p>
+
+<h2 id="overview">Overview</h2>
+
+<p>The Android media router framework enables media app developers and media playback device
+  manufacturers to connect through a common API and common user interface. App developers that
+  implement a {@link android.support.v7.media.MediaRouter} interface can then connect to the
+  framework and play content to devices that participate in the media router framework. Media
+  playback device manufacturers can participate in the framework by publishing a {@link
+  android.support.v7.media.MediaRouteProvider} that allows other applications to connect to and
+  play media on the receiver devices. Figure 1 illustrates how an app connects to a receiving
+  device through the media router framework.</p>
+
+<img src="{@docRoot}images/mediarouter/media-route-provider-framework.png" alt="" id="figure1"/>
+<p class="img-caption">
+  <strong>Figure 1.</strong> Overview of how media route provider classes provide communication
+  from a media app to a receiver device.
+</p>
+
+<p>When you build a media route provider for your receiver device, the provider serves the
+following purposes:</p>
+
+<ul>
+  <li>Describe and publish the capabilities of the receiver device so other apps can discover it
+    and use its playback features.</li>
+  <li>Wrap the programming interface of the receiver device and its communication
+    transport mechanisms to make the device compatible with the media router framework.</li>
+</ul>
+
+
+<h3 id="dist">Distribution of route providers</h3>
+
+<p>A media route provider is distributed as part of an Android app. Your route provider can be
+  made available to other apps by extending
+  {@link android.support.v7.media.MediaRouteProviderService} or wrapping your implementation of
+  {@link android.support.v7.media.MediaRouteProvider} with your own service and declaring an intent
+  filter for the media route provider. These steps allow other apps to discover and make use of
+  your media route.</p>
+
+<p>
+  <strong>Note:</strong> The app containing the media route provider can also include a
+  <a href="{@docRoot}guide/topics/media/mediarouter.html">MediaRouter</a> interface to the
+  route provider, but this is not required.
+</p>
+
+
+<h3 id="playback-types">Types of playback</h3>
+
+<p>There are two main types of playback supported by the media router framework. A media route
+  provider can support one or both types of playback, depending on the capabilities of your playback
+  equipment and the functionality you want to support:</p>
+
+<ul>
+  <li><strong>Remote Playback</strong> — This approach uses the receiver device to handle the
+    content data retrieval, decoding, and playback, while an Android device in the user's hand is
+    used as a remote control. This approach is used by Android apps that support
+    <a href="https://developers.google.com/cast/">Google Cast</a>.</li>
+  <li><strong>Secondary Output</strong> — With this approach, the Android media application
+    retrieves, renders and streams video or music directly to the receiver device. This approach is
+    used to support Wireless Display output on Android.</li>
+</ul>
+
+
+<h3 id="mr-packages">Media router packages</h3>
+
+<p>
+  The media router APIs are provided as part of the Android Support Library version 18 and higher,
+  in the <a href="{@docRoot}tools/support-library/features.html#v7-mediarouter">v7-mediarouter</a>
+  support library. You should use the classes in the
+  {@link android.support.v7.media} package for media route provider functions.
+  These APIs are compatible with devices running Android 2.1 (API level 7) and higher.
+</p>
+
+<p class="caution">
+  <strong>Caution:</strong> There is another set of media router APIs provided in the
+  {@link android.media} class package that have been superseded by the
+  <a href="{@docRoot}tools/support-library/features.html#v7-mediarouter">v7-mediarouter</a>
+  support library. You <em>should not</em> use the {@link android.media} classes for
+  implementing media route provider functions.
+</p>
+
+<p>In order to use the {@link android.support.v7.media} media router classes, you
+  must add the <a href="{@docRoot}tools/support-library/features.html#v7-mediarouter"
+  >v7-mediarouter support library package</a> to your app development project. For more
+  information on adding support libraries to your app development project, see
+  <a href="{@docRoot}tools/support-library/setup.html">Support Library Setup</a>.
+</p>
+
+
+<h2 id="provider-service">Creating a Provider Service</h2>
+
+<p>The media router framework must be able to discover and connect to your media route provider
+  to allow other applications to use your route. In order to do this, the media router framework
+  looks for apps that declare a media route provider intent action. When another app wants to
+  connect to your provider, the framework must be able to invoke and connect to it, so your provider
+  must be encapsulated in a {@link android.app.Service}.</p>
+
+<p>The following example code shows the declaration of a media route provider service and the
+  intent filter in a manifest, which allows it to be discovered and used by the media router
+  framework:</p>
+
+<pre>
+&lt;service android:name=".provider.SampleMediaRouteProviderService"
+    android:label="&#64;string/sample_media_route_provider_service"
+    android:process=":mrp"&gt;
+    &lt;intent-filter&gt;
+        &lt;action android:name="android.media.MediaRouteProviderService" /&gt;
+    &lt;/intent-filter&gt;
+&lt;/service&gt;
+</pre>
+
+<p>This manifest example declares a service that wraps the actual media route provider classes.
+  The Android media router framework provides the
+  {@link android.support.v7.media.MediaRouteProviderService} class for use as a service wrapper for
+  media route providers. The following example code demonstrates how to use this wrapper
+  class:</p>
+
+<pre>
+public class SampleMediaRouteProviderService extends MediaRouteProviderService {
+
+    &#64;Override
+    public MediaRouteProvider onCreateMediaRouteProvider() {
+        return new SampleMediaRouteProvider(this);
+    }
+}
+</pre>
+
+
+<h2 id="route-caps">Specifying Route Capabilities</h2>
+
+<p>Apps connecting to the media router framework can discover your media route through your
+  app's manifest declarations, but they also need to know the capabilities of the media routes you
+  are providing. Media routes can be of different types and have different features, and other apps
+  need to be able to discover these details to determine if they are compatible with your route.</p>
+
+<p>The media router framework allows you to define and publish the capabilities of your media
+  route through {@link android.content.IntentFilter} objects, {@link
+  android.support.v7.media.MediaRouteDescriptor} objects and a {@link
+  android.support.v7.media.MediaRouteProviderDescriptor}. This section explains how to use these
+  classes to publish the details of your media route for other apps.</p>
+
+
+<h3 id="route-cat">Route categories</h3>
+
+<p>As part of the programmatic description of your media route provider, you must specify
+  whether your provider supports remote playback, secondary output, or both. These are the route
+  categories provided by the media router framework:</p>
+
+<ul>
+  <li>{@link android.support.v7.media.MediaControlIntent#CATEGORY_LIVE_AUDIO CATEGORY_LIVE_AUDIO}
+    &mdash; Output of audio to a secondary output device, such as a wireless-enabled music system.
+    </li>
+  <li>{@link android.support.v7.media.MediaControlIntent#CATEGORY_LIVE_VIDEO CATEGORY_LIVE_VIDEO}
+    &mdash; Output of video to a secondary output device, such as Wireless Display devices.</li>
+  <li>{@link android.support.v7.media.MediaControlIntent#CATEGORY_REMOTE_PLAYBACK
+    CATEGORY_REMOTE_PLAYBACK} &mdash; Play video or audio on a separate device which handles media
+    retrieval, decoding, and playback, such as
+    <a href="https://www.google.com/url?q=http://www.google.com/chromecast">Chromecast</a> devices.
+    </li>
+</ul>
+
+<p>In order to include these settings in a description of your media route, you insert them into
+  an {@link android.content.IntentFilter} object, which you later add to a
+  {@link android.support.v7.media.MediaRouteDescriptor} object:</p>
+
+<pre>
+public final class SampleMediaRouteProvider extends MediaRouteProvider {
+    private static final ArrayList&lt;IntentFilter&gt; CONTROL_FILTERS_BASIC;
+    static {
+        IntentFilter videoPlayback = new IntentFilter();
+        <strong>videoPlayback.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK);</strong>
+        CONTROL_FILTERS_BASIC = new ArrayList&lt;IntentFilter&gt;();
+        CONTROL_FILTERS_BASIC.add(videoPlayback);
+    }
+}
+
+</pre>
+
+<p>If you specify the {@link android.support.v7.media.MediaControlIntent#CATEGORY_REMOTE_PLAYBACK
+  CATEGORY_REMOTE_PLAYBACK} intent, you must also define what media types and
+  playback controls are supported by your media route provider. The next section describes how to
+  specify these settings for your device.</p>
+
+
+<h3 id="media-types">Media types and protocols</h3>
+
+<p>A media route provider for a remote playback device must specify the media types and transfer
+  protocols it supports. You specify these settings using the {@link android.content.IntentFilter}
+  class and the {@link android.content.IntentFilter#addDataScheme addDataScheme()} and
+  {@link android.content.IntentFilter#addDataType addDataType()} methods of that object. The
+  following code snippet demonstrates how to define an intent filter for supporting remote video
+  playback using http, https, and Real Time Streaming Protocol (RTSP):</p>
+
+<pre>
+public final class SampleMediaRouteProvider extends MediaRouteProvider {
+
+    private static final ArrayList&lt;IntentFilter&gt; CONTROL_FILTERS_BASIC;
+
+    static {
+        IntentFilter videoPlayback = new IntentFilter();
+        videoPlayback.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK);
+        videoPlayback.addAction(MediaControlIntent.ACTION_PLAY);
+        videoPlayback.addDataScheme("http");
+        videoPlayback.addDataScheme("https");
+        videoPlayback.addDataScheme("rtsp");
+        addDataTypeUnchecked(videoPlayback, "video/*");
+        CONTROL_FILTERS_BASIC = new ArrayList&lt;IntentFilter&gt;();
+        CONTROL_FILTERS_BASIC.add(videoPlayback);
+    }
+    ...
+
+    private static void addDataTypeUnchecked(IntentFilter filter, String type) {
+        try {
+            filter.addDataType(type);
+        } catch (MalformedMimeTypeException ex) {
+            throw new RuntimeException(ex);
+        }
+    }
+}
+
+</pre>
+
+
+<h3 id="playback-ctrls">Playback controls</h3>
+
+<p>A media route provider that offers remote playback must specify the types of media controls
+  it supports. These are the general types of control that media routes can provide:</p>
+
+<ul>
+  <li><strong>Playback controls</strong>, such as play, pause, rewind, and fast-forward.</li>
+  <li><strong>Queuing features</strong>, which allow the sending app to add and remove items
+    from a playlist which is maintained by the receiver device.</li>
+  <li><strong>Session features</strong>, which prevent sending apps from interfering with each
+    other by having the receiver device provide a session id to the requesting app and then checking
+    that id with each subsequent playback control request.</li>
+</ul>
+
+<p>The following code example demonstrates how to construct an intent filter for supporting
+  basic media route playback controls:</p>
+
+<pre>
+public final class SampleMediaRouteProvider extends MediaRouteProvider {
+    private static final ArrayList&lt;IntentFilter&gt; CONTROL_FILTERS_BASIC;
+    static {
+        ...
+        IntentFilter playControls = new IntentFilter();
+        playControls.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK);
+        playControls.addAction(MediaControlIntent.ACTION_SEEK);
+        playControls.addAction(MediaControlIntent.ACTION_GET_STATUS);
+        playControls.addAction(MediaControlIntent.ACTION_PAUSE);
+        playControls.addAction(MediaControlIntent.ACTION_RESUME);
+        playControls.addAction(MediaControlIntent.ACTION_STOP);
+        CONTROL_FILTERS_BASIC = new ArrayList&lt;IntentFilter&gt;();
+        CONTROL_FILTERS_BASIC.add(videoPlayback);
+        CONTROL_FILTERS_BASIC.add(playControls);
+    }
+    ...
+}
+</pre>
+
+<p>For more information about the available playback control intents, see the
+  {@link android.support.v7.media.MediaControlIntent} class.</p>
+
+
+<h3 id="mrpd">MediaRouteProviderDescriptor</h3>
+
+<p>After defining the capabilities of your media route using {@link
+  android.content.IntentFilter} objects, you can then create a descriptor object for publishing to
+  the Android media router framework. This descriptor object contains the specifics of your media
+  route's capabilities so that other applications can determine how to interact with your media
+  route.</p>
+
+<p>The following example code demonstrates how to add the previously created intent filters to a
+  {@link android.support.v7.media.MediaRouteProviderDescriptor} and set the descriptor for use by
+  the media router framework:</p>
+
+<pre>
+public SampleMediaRouteProvider(Context context) {
+    super(context);
+    publishRoutes();
+}
+
+private void publishRoutes() {
+    Resources r = getContext().getResources();
+    // Create a route descriptor using previously created IntentFilters
+    MediaRouteDescriptor routeDescriptor = new MediaRouteDescriptor.Builder(
+            VARIABLE_VOLUME_BASIC_ROUTE_ID,
+            r.getString(R.string.variable_volume_basic_route_name))
+            .setDescription(r.getString(R.string.sample_route_description))
+            .addControlFilters(CONTROL_FILTERS_BASIC)
+            .setPlaybackStream(AudioManager.STREAM_MUSIC)
+            .setPlaybackType(MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE)
+            .setVolumeHandling(MediaRouter.RouteInfo.PLAYBACK_VOLUME_VARIABLE)
+            .setVolumeMax(VOLUME_MAX)
+            .setVolume(mVolume)
+            .build();
+    // Add the route descriptor to the provider descriptor
+    MediaRouteProviderDescriptor providerDescriptor =
+            new MediaRouteProviderDescriptor.Builder()
+            .addRoute(routeDescriptor)
+            .build();
+
+    // Publish the descriptor to the framework
+    setDescriptor(providerDescriptor);
+}
+</pre>
+
+<p>For more information on the available descriptor settings, see the reference documentation
+  for {@link android.support.v7.media.MediaRouteDescriptor} and {@link
+  android.support.v7.media.MediaRouteProviderDescriptor}.</p>
+
+
+<h2 id="ctrl-routes">Controlling Routes</h2>
+
+<p>When an application connects to your media route provider, the provider receives playback
+  commands through the media router framework sent to your route by other apps. To handle these
+  requests, you must provide an implementation of a {@link
+  android.support.v7.media.MediaRouteProvider.RouteController} class, which processes the commands
+  and handles the actual communication to your receiver device.</p>
+
+<p>The media router framework calls the {@link
+  android.support.v7.media.MediaRouteProvider#onCreateRouteController onCreateRouteController()}
+  method of your route provider to obtain an instance of this class and then routes requests to it.
+  These are the key methods of the {@link
+  android.support.v7.media.MediaRouteProvider.RouteController} class, which you must implement for
+  your media route provider:</p>
+
+<ul>
+  <li>{@link android.support.v7.media.MediaRouteProvider.RouteController#onSelect onSelect()}
+    &mdash; Called when an application selects your route for playback. You use this method to do
+    any preparation work that may be required before media playback begins.</li>
+  <li>{@link android.support.v7.media.MediaRouteProvider.RouteController#onControlRequest
+    onControlRequest()} &mdash; Sends specific playback commands to the receiving device.</li>
+  <li>{@link android.support.v7.media.MediaRouteProvider.RouteController#onSetVolume
+    onSetVolume()} &mdash; Sends a request to the receiving device to set the playback volume to a
+    specific value.</li>
+  <li>{@link android.support.v7.media.MediaRouteProvider.RouteController#onUpdateVolume
+    onUpdateVolume()} &mdash; Sends a request to the receiving device to modify the playback
+    volume by a specified amount.</li>
+  <li>{@link android.support.v7.media.MediaRouteProvider.RouteController#onUnselect
+    onUnselect()} &mdash; Called when an application unselects a route.</li>
+  <li>{@link android.support.v7.media.MediaRouteProvider.RouteController#onRelease onRelease()}
+    &mdash; Called when the route is no longer needed by the framework, allowing it to free its
+    resources.</li>
+</ul>
+
+<p>All playback control requests, except for volume changes, are directed to the {@link
+  android.support.v7.media.MediaRouteProvider.RouteController#onControlRequest onControlRequest()}
+  method. Your implementation of this method must parse the control requests and respond to them
+  appropriately. Here is an example implementation of this method which processes commands for a
+  remote playback media route:</p>
+
+<pre>
+private final class SampleRouteController extends
+        MediaRouteProvider.RouteController {
+    ...
+
+    &#64;Override
+    public boolean onControlRequest(Intent intent, ControlRequestCallback callback) {
+
+        String action = intent.getAction();
+
+        if (intent.hasCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)) {
+            boolean success = false;
+            if (action.equals(MediaControlIntent.ACTION_PLAY)) {
+                success = handlePlay(intent, callback);
+            } else if (action.equals(MediaControlIntent.ACTION_ENQUEUE)) {
+                success = handleEnqueue(intent, callback);
+            } else if (action.equals(MediaControlIntent.ACTION_REMOVE)) {
+                success = handleRemove(intent, callback);
+            } else if (action.equals(MediaControlIntent.ACTION_SEEK)) {
+                success = handleSeek(intent, callback);
+            } else if (action.equals(MediaControlIntent.ACTION_GET_STATUS)) {
+                success = handleGetStatus(intent, callback);
+            } else if (action.equals(MediaControlIntent.ACTION_PAUSE)) {
+                success = handlePause(intent, callback);
+            } else if (action.equals(MediaControlIntent.ACTION_RESUME)) {
+                success = handleResume(intent, callback);
+            } else if (action.equals(MediaControlIntent.ACTION_STOP)) {
+                success = handleStop(intent, callback);
+            } else if (action.equals(MediaControlIntent.ACTION_START_SESSION)) {
+                success = handleStartSession(intent, callback);
+            } else if (action.equals(MediaControlIntent.ACTION_GET_SESSION_STATUS)) {
+                success = handleGetSessionStatus(intent, callback);
+            } else if (action.equals(MediaControlIntent.ACTION_END_SESSION)) {
+                success = handleEndSession(intent, callback);
+            }
+
+            Log.d(TAG, mSessionManager.toString());
+            return success;
+        }
+        return false;
+    }
+    ...
+}
+</pre>
+
+<p>It is important to understand that the {@link
+  android.support.v7.media.MediaRouteProvider.RouteController} class is intended to act as a wrapper
+  for the API to your media playback equipment. The implementation of the methods in this class is
+  entirely dependent on the programmatic interface provided by your receiving device.</p>
diff --git a/docs/html/guide/topics/media/mediarouter.jd b/docs/html/guide/topics/media/mediarouter.jd
index 1b10265..e0bf889 100644
--- a/docs/html/guide/topics/media/mediarouter.jd
+++ b/docs/html/guide/topics/media/mediarouter.jd
@@ -1,5 +1,5 @@
-page.title=MediaRouter
-page.tags="cast","chromecast","wireless display","miracast"
+page.title=Media Router
+page.tags="mediarouter","cast","chromecast","wireless display","miracast"
 @jd:body
 
 <div id="qv-wrapper">
@@ -36,6 +36,10 @@
       <li>{@link android.support.v7.media.MediaRouter.Callback}</li>
       <li>{@link android.support.v7.media.MediaRouteProvider}</li>
     </ol>
+    <h2>Related Samples</h2>
+    <ol>
+      <li><a href="{@docRoot}guide/topics/media/mediarouter.html">MediaRouter</a></li>
+    </ol>
   </div>
 </div>
 
@@ -105,15 +109,17 @@
   (API level 7) and higher.
 </p>
 
-<p class="note">
-  <strong>Note:</strong> There is another set of media router APIs provided in the
+<p class="caution">
+  <strong>Caution:</strong> There is another set of media router APIs provided in the
   {@link android.media} that have been superseded by the v7-mediarouter support library.
   You <em>should not</em> use the {@link android.media} classes for media router functions.
 </p>
 
 <p>In order to use the {@link android.support.v7.media} media router classes, you must add
   the <a href="{@docRoot}tools/support-library/features.html#v7-mediarouter">v7-mediarouter
-  support library package</a> to your app development project.
+  support library package</a> to your app development project.  For more
+  information on adding support libraries to your app development project, see
+  <a href="{@docRoot}tools/support-library/setup.html">Support Library Setup</a>.
 </p>
 
 
@@ -211,9 +217,9 @@
     CATEGORY_LIVE_VIDEO} &mdash; Output of video to a secondary output device, such as Wireless
     Display devices.</li>
   <li>{@link android.support.v7.media.MediaControlIntent#CATEGORY_REMOTE_PLAYBACK
-    CATEGORY_REMOTE_PLAYBACK} &mdash; Play video or audio on a separate device that supports the
-    <a href="https://developers.google.com/cast/">Google Cast</a> remote control protocol, such
-    as <a href="https://www.google.com/url?q=http://www.google.com/chromecast">Chromecast</a>.
+    CATEGORY_REMOTE_PLAYBACK} &mdash; Play video or audio on a separate device that handles media
+    retrieval, decoding, and playback, such as
+    <a href="https://www.google.com/url?q=http://www.google.com/chromecast">Chromecast</a> devices.
     </li>
 </ul>
 
@@ -279,7 +285,7 @@
 <p>In order to connect to a media route selected by the user, your app must obtain the {@link
   android.support.v7.media.MediaRouter} framework object and then attach a {@link
   android.support.v7.media.MediaRouter.Callback} object. The callback object receives messages
-  from the media router framework when a route selected, changed or disconnected by the user.</p>
+  from the media router framework when a route is selected, changed, or disconnected by the user.</p>
 
 <p>To obtain an instance of the {@link android.support.v7.media.MediaRouter} framework object,
   call {@link android.support.v7.media.MediaRouter#getInstance MediaRouter.getInstance()}
@@ -299,11 +305,11 @@
 <p>The media router framework communicates with an app through a callback object that
   you attach to the {@link android.support.v7.media.MediaRouter} framework object. An app
   that uses the media router framework must extend the {@link
-  android.support.v7.media.MediaRouter.Callback} object to receive messages when a media route is
-  connected and provide content to the connected device through that route.</p>
+  android.support.v7.media.MediaRouter.Callback} object in order to receive messages when a
+  media route is connected.</p>
 
-<p>There are several methods in the callback that can be overwritten to receive messages about
-  media router events. At the minimum, your implementation of the {@link
+<p>There are several methods in the callback that you can override to receive information about
+  media router events. At minimum, your implementation of the {@link
   android.support.v7.media.MediaRouter.Callback} class should override the following
   methods:</p>
 
@@ -440,12 +446,12 @@
 
 <p class="note">
   <strong>Note:</strong> The media route framework also provides a
-  {@link android.support.v7.app.MediaRouteDiscoveryFragment} class which takes care of adding and
-  removing the call back for an activity.
+  {@link android.support.v7.app.MediaRouteDiscoveryFragment} class, which takes care of adding and
+  removing the callback for an activity.
 </p>
 
 <p>Now when you run your application, you should see a Cast button appear in your activity.
-  When you press the button the media router framework, a route selection dialog appears as shown
+  When you touch the button, a route selection dialog appears as shown
   in figure 3, allowing your user to select an available media route. Make sure you have a
   supported device available on your local network when testing this interface.</p>
 
diff --git a/docs/html/guide/topics/resources/index.jd b/docs/html/guide/topics/resources/index.jd
index 386abf5..b85170b 100644
--- a/docs/html/guide/topics/resources/index.jd
+++ b/docs/html/guide/topics/resources/index.jd
@@ -2,6 +2,8 @@
 page.landing=true
 page.landing.intro=It takes more than just code to build a great app. Resources are the additional files and static content that your code uses, such as bitmaps, layout definitions, user interface strings, animation instructions, and more.  
 page.landing.image=images/develop/resources.png
+page.image=/images/develop/resources.png
+page.metaDescription=Developer guide about how to use resources in your Android apps.
 
 @jd:body
 
diff --git a/docs/html/guide/topics/resources/localization.jd b/docs/html/guide/topics/resources/localization.jd
index 7288aeb..e86d4c9 100644
--- a/docs/html/guide/topics/resources/localization.jd
+++ b/docs/html/guide/topics/resources/localization.jd
@@ -25,7 +25,7 @@
 

 <h2>See also</h2>

   <ol>

-    <li><a href="{@docRoot}distribute/googleplay/publish/localizing.html">Localization Checklist</a></li>

+    <li><a href="{@docRoot}distribute/tools/localization-checklist.html">Localization Checklist</a></li>

     <li><a href="{@docRoot}guide/topics/resources/providing-resources.html">Providing Resources</a></li>

     <li><a href="{@docRoot}guide/topics/ui/declaring-layout.html">Layouts</a></li>

     <li><a href="{@docRoot}reference/android/app/Activity.html#ActivityLifecycle">Activity Lifecycle</a></li>

@@ -307,7 +307,7 @@
 <h2 id="checklist">Localization Checklist</h2>

 

 <p>For a complete overview of the process of localizing and distributing an Android application,

-see the <a href="{@docRoot}distribute/googleplay/publish/localizing.html">Localization

+see the <a href="{@docRoot}distribute/tools/localization-checklist.html">Localization

 Checklist</a> document.</p>

 

 <h2 id="strategies">Localization Tips</h2>

diff --git a/docs/html/guide/topics/resources/providing-resources.jd b/docs/html/guide/topics/resources/providing-resources.jd
index aec7fa7..bf16630 100644
--- a/docs/html/guide/topics/resources/providing-resources.jd
+++ b/docs/html/guide/topics/resources/providing-resources.jd
@@ -562,6 +562,7 @@
         <code>desk</code><br/>
         <code>television<br/>
         <code>appliance</code>
+        <code>watch</code>
       </td>
       <td>
         <ul class="nolist">
@@ -573,8 +574,9 @@
           non-pointer interaction</li>
           <li>{@code appliance}: Device is serving as an appliance, with
           no display</li>
+          <li>{@code watch}: Device has a display and is worn on the wrist</li>
         </ul>
-        <p><em>Added in API level 8, television added in API 13.</em></p>
+        <p><em>Added in API level 8, television added in API 13, watch added in API 20.</em></p>
         <p>For information about how your app can respond when the device is inserted into or
         removed from a dock, read <a 
         href="{@docRoot}training/monitoring-device-state/docking-monitoring.html">Determining
diff --git a/docs/html/guide/topics/resources/string-resource.jd b/docs/html/guide/topics/resources/string-resource.jd
index 5a96ba1..e2326ec 100644
--- a/docs/html/guide/topics/resources/string-resource.jd
+++ b/docs/html/guide/topics/resources/string-resource.jd
@@ -20,9 +20,6 @@
 information about styling and formatting strings, see the section about <a
 href="#FormattingAndStyling">Formatting and Styling</a>.</p>
 
-
-
-
 <h2 id="String">String</h2>
 
 <p>A single string that can be referenced from the application or from other resource files (such
@@ -433,7 +430,7 @@
 
 
 
-<h3>Styling with HTML markup</h3>
+<h3 id="StylingWithHTML">Styling with HTML markup</h3>
 
 <p>You can add styling to your strings with HTML markup. For example:</p>
 <pre>
@@ -497,5 +494,107 @@
 CharSequence styledText = Html.fromHtml(text);
 </pre>
 
+<h2 id="StylingWithSpannables">Styling with Spannables</h2>
+<p>
+A {@link android.text.Spannable} is a text object that you can style with
+typeface properties such as color and font weight. You use
+{@link android.text.SpannableStringBuilder} to build
+your text and then apply styles defined in the {@link android.text.style}
+package to the text.
+</p>
 
+<p>You can use the following helper methods to set up much of the work
+of creating spannable text:</p>
 
+<pre style="pretty-print">
+/**
+ * Returns a CharSequence that concatenates the specified array of CharSequence
+ * objects and then applies a list of zero or more tags to the entire range.
+ *
+ * @param content an array of character sequences to apply a style to
+ * @param tags the styled span objects to apply to the content
+ *        such as android.text.style.StyleSpan
+ *
+ */
+private static CharSequence apply(CharSequence[] content, Object... tags) {
+    SpannableStringBuilder text = new SpannableStringBuilder();
+    openTags(text, tags);
+    for (CharSequence item : content) {
+        text.append(item);
+    }
+    closeTags(text, tags);
+    return text;
+}
+
+/**
+ * Iterates over an array of tags and applies them to the beginning of the specified
+ * Spannable object so that future text appended to the text will have the styling
+ * applied to it. Do not call this method directly.
+ */
+private static void openTags(Spannable text, Object[] tags) {
+    for (Object tag : tags) {
+        text.setSpan(tag, 0, 0, Spannable.SPAN_MARK_MARK);
+    }
+}
+
+/**
+ * "Closes" the specified tags on a Spannable by updating the spans to be
+ * endpoint-exclusive so that future text appended to the end will not take
+ * on the same styling. Do not call this method directly.
+ */
+private static void closeTags(Spannable text, Object[] tags) {
+    int len = text.length();
+    for (Object tag : tags) {
+        if (len > 0) {
+            text.setSpan(tag, 0, len, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+        } else {
+            text.removeSpan(tag);
+        }
+    }
+}
+</pre>
+
+<p>
+The following <code>bold</code>, <code>italic</code>, and <code>color</code>
+methods show you how to call the helper methods to apply
+styles defined in the {@link android.text.style} package. You
+can create similar methods to do other types of text styling.
+</p>
+
+<pre style="pretty-print">
+/**
+ * Returns a CharSequence that applies boldface to the concatenation
+ * of the specified CharSequence objects.
+ */
+public static CharSequence bold(CharSequence... content) {
+    return apply(content, new StyleSpan(Typeface.BOLD));
+}
+
+/**
+ * Returns a CharSequence that applies italics to the concatenation
+ * of the specified CharSequence objects.
+ */
+public static CharSequence italic(CharSequence... content) {
+    return apply(content, new StyleSpan(Typeface.ITALIC));
+}
+
+/**
+ * Returns a CharSequence that applies a foreground color to the
+ * concatenation of the specified CharSequence objects.
+ */
+public static CharSequence color(int color, CharSequence... content) {
+    return apply(content, new ForegroundColorSpan(color));
+}
+</pre>
+
+<p>
+Here's an example of how to chain these methods to create a character sequence
+with different types of styling applied to individual words:
+</p>
+
+<pre style="pretty-print">
+// Create an italic "hello, " a red "world",
+// and bold the entire sequence.
+CharSequence text = bold(italic(res.getString(R.string.hello)),
+    color(Color.RED, res.getString(R.string.world)));
+</pre>
\ No newline at end of file
diff --git a/docs/html/guide/topics/ui/accessibility/index.jd b/docs/html/guide/topics/ui/accessibility/index.jd
index 56efc4c..dcc22d7 100644
--- a/docs/html/guide/topics/ui/accessibility/index.jd
+++ b/docs/html/guide/topics/ui/accessibility/index.jd
@@ -1,5 +1,9 @@
 page.title=Accessibility
 parent.title=User Interface
+page.metaDescription=How to make your apps accessible to users with visual, physical, or other limitations. Robust support will increase your app's user base.
+
+page.tags="accessibility"
+page.image=/design/media/accessibility_contentdesc.png
 parent.link=../index.html
 @jd:body
 
diff --git a/docs/html/guide/topics/ui/actionbar.jd b/docs/html/guide/topics/ui/actionbar.jd
index 3173ff1..f01d4bf 100644
--- a/docs/html/guide/topics/ui/actionbar.jd
+++ b/docs/html/guide/topics/ui/actionbar.jd
@@ -1126,8 +1126,8 @@
 uses a string array as the data source:</p>
 
 <pre>
-SpinnerAdapter mSpinnerAdapter = ArrayAdapter.createFromResource(this, R.array.action_list,
-          android.R.layout.simple_spinner_dropdown_item);
+SpinnerAdapter mSpinnerAdapter = ArrayAdapter.createFromResource(this,
+        R.array.action_list, android.R.layout.simple_spinner_dropdown_item);
 </pre>
 
 <p>The {@link android.widget.ArrayAdapter#createFromResource createFromResource()} method takes
@@ -1145,7 +1145,7 @@
         &lt;item&gt;Venus&lt;/item&gt;
         &lt;item&gt;Earth&lt;/item&gt;
     &lt;/string-array&gt;
-&lt;/pre&gt;
+&lt;/resources&gt;
 </pre>
 
 <p>The {@link android.widget.ArrayAdapter} returned by {@link
@@ -1179,10 +1179,13 @@
   public boolean onNavigationItemSelected(int position, long itemId) {
     // Create new fragment from our own Fragment class
     ListContentFragment newFragment = new ListContentFragment();
-    FragmentTransaction ft = openFragmentTransaction();
+    FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
+
     // Replace whatever is in the fragment container with this fragment
-    //  and give the fragment a tag name equal to the string at the position selected
+    // and give the fragment a tag name equal to the string at the position
+    // selected
     ft.replace(R.id.fragment_container, newFragment, strings[position]);
+
     // Apply changes
     ft.commit();
     return true;
@@ -1210,7 +1213,8 @@
     &#64;Override
     public void onAttach(Activity activity) {
       // This is the first callback received; here we can set the text for
-      // the fragment as defined by the tag specified during the fragment transaction
+      // the fragment as defined by the tag specified during the fragment
+      // transaction
       super.onAttach(activity);
       mText = getTag();
     }
diff --git a/docs/html/guide/topics/ui/notifiers/notifications.jd b/docs/html/guide/topics/ui/notifiers/notifications.jd
index 3b1292e..59c2269 100644
--- a/docs/html/guide/topics/ui/notifiers/notifications.jd
+++ b/docs/html/guide/topics/ui/notifiers/notifications.jd
@@ -16,6 +16,7 @@
       <li><a href="#Required">Required notification contents</a></li>
       <li><a href="#Optional">Optional notification contents and settings</a></li>
       <li><a href="#Actions">Notification actions</a></li>
+      <li><a href="#Priority">Notification priority</a></li>
       <li><a href="#SimpleNotification">Creating a simple notification</a></li>
       <li><a href="#ApplyStyle">Applying a big view style to a notification</a></li>
       <li><a href="#Compatibility">Handling compatibility</a></li>
@@ -290,6 +291,26 @@
     {@link android.support.v4.app.NotificationCompat.Builder}.
 </p>
 <!-- ------------------------------------------------------------------------------------------ -->
+<h3 id="Priority">Notification priority</h3>
+<p>
+    If you wish, you can set the priority of a notification. The priority acts
+    as a hint to the device UI about how the notification should be displayed.
+    To set a notification's priority, call {@link
+    android.support.v4.app.NotificationCompat.Builder#setPriority(int)
+    NotificationCompat.Builder.setPriority()} and pass in one of the {@link
+    android.support.v4.app.NotificationCompat} priority constants. There are
+    five priority levels, ranging from {@link
+    android.support.v4.app.NotificationCompat#PRIORITY_MIN} (-2) to {@link
+    android.support.v4.app.NotificationCompat#PRIORITY_MAX} (2); if not set, the
+    priority defaults to {@link
+    android.support.v4.app.NotificationCompat#PRIORITY_DEFAULT} (0).
+</p>
+<p> For information about setting an appropriate priority level, see "Correctly
+    set and manage notification priority" in the <a
+    href="{@docRoot}design/patterns/notifications.html">Notifications</a> Design
+    guide.
+</p>
+<!-- ------------------------------------------------------------------------------------------ -->
 <h3 id="SimpleNotification">Creating a simple notification</h3>
 <p>
     The following snippet illustrates a simple notification that specifies an activity to open when
diff --git a/docs/html/images/blog.jpg b/docs/html/images/blog.jpg
new file mode 100644
index 0000000..a3ee7d8
--- /dev/null
+++ b/docs/html/images/blog.jpg
Binary files differ
diff --git a/docs/html/images/device-art-ex-crop.jpg b/docs/html/images/device-art-ex-crop.jpg
new file mode 100644
index 0000000..42c769b
--- /dev/null
+++ b/docs/html/images/device-art-ex-crop.jpg
Binary files differ
diff --git a/docs/html/images/gcm/CCS-ack.png b/docs/html/images/gcm/CCS-ack.png
index bce2ab2..4633157 100644
--- a/docs/html/images/gcm/CCS-ack.png
+++ b/docs/html/images/gcm/CCS-ack.png
Binary files differ
diff --git a/docs/html/images/gp-about-0.jpg b/docs/html/images/gp-about-0.jpg
new file mode 100644
index 0000000..2dd6a8c
--- /dev/null
+++ b/docs/html/images/gp-about-0.jpg
Binary files differ
diff --git a/docs/html/images/gp-about-listing.jpg b/docs/html/images/gp-about-listing.jpg
new file mode 100644
index 0000000..256c051
--- /dev/null
+++ b/docs/html/images/gp-about-listing.jpg
Binary files differ
diff --git a/docs/html/images/gp-about-picks1.jpg b/docs/html/images/gp-about-picks1.jpg
new file mode 100644
index 0000000..555bd7b
--- /dev/null
+++ b/docs/html/images/gp-about-picks1.jpg
Binary files differ
diff --git a/docs/html/images/gp-about-picks2.jpg b/docs/html/images/gp-about-picks2.jpg
new file mode 100644
index 0000000..ec25e74
--- /dev/null
+++ b/docs/html/images/gp-about-picks2.jpg
Binary files differ
diff --git a/docs/html/images/gp-about-picks3.jpg b/docs/html/images/gp-about-picks3.jpg
new file mode 100644
index 0000000..eb57da9
--- /dev/null
+++ b/docs/html/images/gp-about-picks3.jpg
Binary files differ
diff --git a/docs/html/images/gp-about-top.jpg b/docs/html/images/gp-about-top.jpg
new file mode 100644
index 0000000..01a2744
--- /dev/null
+++ b/docs/html/images/gp-about-top.jpg
Binary files differ
diff --git a/docs/html/images/gp-androidify.png b/docs/html/images/gp-androidify.png
new file mode 100644
index 0000000..122d596
--- /dev/null
+++ b/docs/html/images/gp-androidify.png
Binary files differ
diff --git a/docs/html/images/gp-apps-home.png b/docs/html/images/gp-apps-home.png
deleted file mode 100644
index 851f722..0000000
--- a/docs/html/images/gp-apps-home.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-badge-jp.png b/docs/html/images/gp-badge-jp.png
new file mode 100644
index 0000000..00b5d1f
--- /dev/null
+++ b/docs/html/images/gp-badge-jp.png
Binary files differ
diff --git a/docs/html/images/gp-badges-set.png b/docs/html/images/gp-badges-set.png
new file mode 100644
index 0000000..e2e0e94
--- /dev/null
+++ b/docs/html/images/gp-badges-set.png
Binary files differ
diff --git a/docs/html/images/gp-balance.png b/docs/html/images/gp-balance.png
new file mode 100644
index 0000000..7802bcc
--- /dev/null
+++ b/docs/html/images/gp-balance.png
Binary files differ
diff --git a/docs/html/images/gp-build-buzz-yt.png b/docs/html/images/gp-build-buzz-yt.png
new file mode 100644
index 0000000..7901aa5
--- /dev/null
+++ b/docs/html/images/gp-build-buzz-yt.png
Binary files differ
diff --git a/docs/html/images/gp-buzz-1.jpg b/docs/html/images/gp-buzz-1.jpg
new file mode 100644
index 0000000..ce2444b
--- /dev/null
+++ b/docs/html/images/gp-buzz-1.jpg
Binary files differ
diff --git a/docs/html/images/gp-collectibles.png b/docs/html/images/gp-collectibles.png
deleted file mode 100644
index a63cd50..0000000
--- a/docs/html/images/gp-collectibles.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-community-0.png b/docs/html/images/gp-community-0.png
new file mode 100644
index 0000000..bb8fde2
--- /dev/null
+++ b/docs/html/images/gp-community-0.png
Binary files differ
diff --git a/docs/html/images/gp-core-quality.png b/docs/html/images/gp-core-quality.png
new file mode 100644
index 0000000..196459f
--- /dev/null
+++ b/docs/html/images/gp-core-quality.png
Binary files differ
diff --git a/docs/html/images/gp-dc-ab.png b/docs/html/images/gp-dc-ab.png
new file mode 100644
index 0000000..0604a1b
--- /dev/null
+++ b/docs/html/images/gp-dc-ab.png
Binary files differ
diff --git a/docs/html/images/gp-dc-inapp.jpg b/docs/html/images/gp-dc-inapp.jpg
new file mode 100644
index 0000000..e830e31
--- /dev/null
+++ b/docs/html/images/gp-dc-inapp.jpg
Binary files differ
diff --git a/docs/html/images/gp-dc-invite.png b/docs/html/images/gp-dc-invite.png
new file mode 100644
index 0000000..403b53d
--- /dev/null
+++ b/docs/html/images/gp-dc-invite.png
Binary files differ
diff --git a/docs/html/images/gp-dc-startscreen.jpg b/docs/html/images/gp-dc-startscreen.jpg
new file mode 100644
index 0000000..afaa91b
--- /dev/null
+++ b/docs/html/images/gp-dc-startscreen.jpg
Binary files differ
diff --git a/docs/html/images/gp-details-pages-magicpiano.png b/docs/html/images/gp-details-pages-magicpiano.png
deleted file mode 100644
index 4bb1962..0000000
--- a/docs/html/images/gp-details-pages-magicpiano.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-details-ww.png b/docs/html/images/gp-details-ww.png
deleted file mode 100644
index ccc522c..0000000
--- a/docs/html/images/gp-details-ww.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-e-value.png b/docs/html/images/gp-e-value.png
new file mode 100644
index 0000000..86c8f86
--- /dev/null
+++ b/docs/html/images/gp-e-value.png
Binary files differ
diff --git a/docs/html/images/gp-ecom-0.png b/docs/html/images/gp-ecom-0.png
new file mode 100644
index 0000000..22b6040
--- /dev/null
+++ b/docs/html/images/gp-ecom-0.png
Binary files differ
diff --git a/docs/html/images/gp-edu-monetize.png b/docs/html/images/gp-edu-monetize.png
new file mode 100644
index 0000000..6db273c
--- /dev/null
+++ b/docs/html/images/gp-edu-monetize.png
Binary files differ
diff --git a/docs/html/images/gp-edu-optin-console.jpg b/docs/html/images/gp-edu-optin-console.jpg
new file mode 100644
index 0000000..239b966
--- /dev/null
+++ b/docs/html/images/gp-edu-optin-console.jpg
Binary files differ
diff --git a/docs/html/images/gp-edu-quality.png b/docs/html/images/gp-edu-quality.png
new file mode 100644
index 0000000..b103483
--- /dev/null
+++ b/docs/html/images/gp-edu-quality.png
Binary files differ
diff --git a/docs/html/images/gp-engage-0.jpg b/docs/html/images/gp-engage-0.jpg
new file mode 100644
index 0000000..b4f44b5
--- /dev/null
+++ b/docs/html/images/gp-engage-0.jpg
Binary files differ
diff --git a/docs/html/images/gp-engage-5.jpg b/docs/html/images/gp-engage-5.jpg
new file mode 100644
index 0000000..10fa0c2
--- /dev/null
+++ b/docs/html/images/gp-engage-5.jpg
Binary files differ
diff --git a/docs/html/images/gp-engage-6.jpg b/docs/html/images/gp-engage-6.jpg
new file mode 100644
index 0000000..2da09e1
--- /dev/null
+++ b/docs/html/images/gp-engage-6.jpg
Binary files differ
diff --git a/docs/html/images/gp-engage-9.jpg b/docs/html/images/gp-engage-9.jpg
new file mode 100644
index 0000000..46b94f0
--- /dev/null
+++ b/docs/html/images/gp-engage-9.jpg
Binary files differ
diff --git a/docs/html/images/gp-engage-share-plus.png b/docs/html/images/gp-engage-share-plus.png
new file mode 100644
index 0000000..a1aa46e
--- /dev/null
+++ b/docs/html/images/gp-engage-share-plus.png
Binary files differ
diff --git a/docs/html/images/gp-engage-smule.jpg b/docs/html/images/gp-engage-smule.jpg
new file mode 100644
index 0000000..087da79
--- /dev/null
+++ b/docs/html/images/gp-engage-smule.jpg
Binary files differ
diff --git a/docs/html/images/gp-expand-2.jpg b/docs/html/images/gp-expand-2.jpg
new file mode 100644
index 0000000..a7b6916
--- /dev/null
+++ b/docs/html/images/gp-expand-2.jpg
Binary files differ
diff --git a/docs/html/images/gp-expand-4.jpg b/docs/html/images/gp-expand-4.jpg
new file mode 100644
index 0000000..1d5b1a1
--- /dev/null
+++ b/docs/html/images/gp-expand-4.jpg
Binary files differ
diff --git a/docs/html/images/gp-expand-5.jpg b/docs/html/images/gp-expand-5.jpg
new file mode 100644
index 0000000..b2b2264
--- /dev/null
+++ b/docs/html/images/gp-expand-5.jpg
Binary files differ
diff --git a/docs/html/images/gp-freemium-0.jpg b/docs/html/images/gp-freemium-0.jpg
new file mode 100644
index 0000000..767c1f3
--- /dev/null
+++ b/docs/html/images/gp-freemium-0.jpg
Binary files differ
diff --git a/docs/html/images/gp-freemium-1.jpg b/docs/html/images/gp-freemium-1.jpg
new file mode 100644
index 0000000..1e509c5
--- /dev/null
+++ b/docs/html/images/gp-freemium-1.jpg
Binary files differ
diff --git a/docs/html/images/gp-games-home.png b/docs/html/images/gp-games-home.png
deleted file mode 100644
index 81b7f7a..0000000
--- a/docs/html/images/gp-games-home.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-growth-downloads.png b/docs/html/images/gp-growth-downloads.png
deleted file mode 100644
index 4a4b194..0000000
--- a/docs/html/images/gp-growth-downloads.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-launch-checklist-1.png b/docs/html/images/gp-launch-checklist-1.png
new file mode 100644
index 0000000..069cd69
--- /dev/null
+++ b/docs/html/images/gp-launch-checklist-1.png
Binary files differ
diff --git a/docs/html/images/gp-linking-ex-crop.png b/docs/html/images/gp-linking-ex-crop.png
new file mode 100644
index 0000000..c108651
--- /dev/null
+++ b/docs/html/images/gp-linking-ex-crop.png
Binary files differ
diff --git a/docs/html/images/gp-listing-0.jpg b/docs/html/images/gp-listing-0.jpg
new file mode 100644
index 0000000..a204f9f
--- /dev/null
+++ b/docs/html/images/gp-listing-0.jpg
Binary files differ
diff --git a/docs/html/images/gp-listing-1.png b/docs/html/images/gp-listing-1.png
new file mode 100644
index 0000000..ed15d96
--- /dev/null
+++ b/docs/html/images/gp-listing-1.png
Binary files differ
diff --git a/docs/html/images/gp-listing-2.jpg b/docs/html/images/gp-listing-2.jpg
new file mode 100644
index 0000000..73304f4
--- /dev/null
+++ b/docs/html/images/gp-listing-2.jpg
Binary files differ
diff --git a/docs/html/images/gp-listing-3.jpg b/docs/html/images/gp-listing-3.jpg
new file mode 100644
index 0000000..a4def2e
--- /dev/null
+++ b/docs/html/images/gp-listing-3.jpg
Binary files differ
diff --git a/docs/html/images/gp-listing-4.jpg b/docs/html/images/gp-listing-4.jpg
new file mode 100644
index 0000000..f580f86
--- /dev/null
+++ b/docs/html/images/gp-listing-4.jpg
Binary files differ
diff --git a/docs/html/images/gp-localization-trans-0.png b/docs/html/images/gp-localization-trans-0.png
new file mode 100644
index 0000000..2e7b73e
--- /dev/null
+++ b/docs/html/images/gp-localization-trans-0.png
Binary files differ
diff --git a/docs/html/images/gp-optimize-analytics.png b/docs/html/images/gp-optimize-analytics.png
new file mode 100644
index 0000000..81298d0
--- /dev/null
+++ b/docs/html/images/gp-optimize-analytics.png
Binary files differ
diff --git a/docs/html/images/gp-optimize-speed.png b/docs/html/images/gp-optimize-speed.png
new file mode 100644
index 0000000..6ebb995
--- /dev/null
+++ b/docs/html/images/gp-optimize-speed.png
Binary files differ
diff --git a/docs/html/images/gp-optimize.png b/docs/html/images/gp-optimize.png
new file mode 100644
index 0000000..e8388ea
--- /dev/null
+++ b/docs/html/images/gp-optimize.png
Binary files differ
diff --git a/docs/html/images/gp-optimizing-chat-bubbles.png b/docs/html/images/gp-optimizing-chat-bubbles.png
new file mode 100644
index 0000000..71ac767
--- /dev/null
+++ b/docs/html/images/gp-optimizing-chat-bubbles.png
Binary files differ
diff --git a/docs/html/images/gp-optimizing-image-4.jpg b/docs/html/images/gp-optimizing-image-4.jpg
new file mode 100644
index 0000000..949ca81
--- /dev/null
+++ b/docs/html/images/gp-optimizing-image-4.jpg
Binary files differ
diff --git a/docs/html/images/gp-payments-1.png b/docs/html/images/gp-payments-1.png
new file mode 100644
index 0000000..6eaca93
--- /dev/null
+++ b/docs/html/images/gp-payments-1.png
Binary files differ
diff --git a/docs/html/images/gp-policy-ads-eula-violation.png b/docs/html/images/gp-policy-ads-eula-violation.png
deleted file mode 100644
index 204c320..0000000
--- a/docs/html/images/gp-policy-ads-eula-violation.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-policy-ads-impersonate-violation-app-ui.png b/docs/html/images/gp-policy-ads-impersonate-violation-app-ui.png
deleted file mode 100644
index a2a39a9..0000000
--- a/docs/html/images/gp-policy-ads-impersonate-violation-app-ui.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-policy-ads-impersonate-violation-sys-warning.png b/docs/html/images/gp-policy-ads-impersonate-violation-sys-warning.png
deleted file mode 100644
index f323b06..0000000
--- a/docs/html/images/gp-policy-ads-impersonate-violation-sys-warning.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-policy-ads-impersonate-violation.png b/docs/html/images/gp-policy-ads-impersonate-violation.png
deleted file mode 100644
index 385ae6e..0000000
--- a/docs/html/images/gp-policy-ads-impersonate-violation.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-policy-ads-interstitial-violation.png b/docs/html/images/gp-policy-ads-interstitial-violation.png
deleted file mode 100644
index 4871493..0000000
--- a/docs/html/images/gp-policy-ads-interstitial-violation.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-policy-ads-maturity-violation.png b/docs/html/images/gp-policy-ads-maturity-violation.png
deleted file mode 100644
index d41870e..0000000
--- a/docs/html/images/gp-policy-ads-maturity-violation.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-policy-ads-notif-attr-violation.png b/docs/html/images/gp-policy-ads-notif-attr-violation.png
deleted file mode 100644
index 3d6393b..0000000
--- a/docs/html/images/gp-policy-ads-notif-attr-violation.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-policy-ads-notif-attr.png b/docs/html/images/gp-policy-ads-notif-attr.png
deleted file mode 100644
index da39cfb..0000000
--- a/docs/html/images/gp-policy-ads-notif-attr.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-policy-ads-paywall-violation.png b/docs/html/images/gp-policy-ads-paywall-violation.png
deleted file mode 100644
index 8bbfd1b..0000000
--- a/docs/html/images/gp-policy-ads-paywall-violation.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-policy-ads-paywall.png b/docs/html/images/gp-policy-ads-paywall.png
deleted file mode 100644
index e7b1e19..0000000
--- a/docs/html/images/gp-policy-ads-paywall.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-policy-ads-terms.png b/docs/html/images/gp-policy-ads-terms.png
deleted file mode 100644
index dcbdf4a..0000000
--- a/docs/html/images/gp-policy-ads-terms.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-policy-ip-copyright-violation.png b/docs/html/images/gp-policy-ip-copyright-violation.png
deleted file mode 100644
index a4e96a8..0000000
--- a/docs/html/images/gp-policy-ip-copyright-violation.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-policy-ip-impersonation-violation.png b/docs/html/images/gp-policy-ip-impersonation-violation.png
deleted file mode 100644
index b1d9923..0000000
--- a/docs/html/images/gp-policy-ip-impersonation-violation.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-policy-ip-trademark-violation.png b/docs/html/images/gp-policy-ip-trademark-violation.png
deleted file mode 100644
index c05b67b..0000000
--- a/docs/html/images/gp-policy-ip-trademark-violation.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-policy-spam-negreview.png b/docs/html/images/gp-policy-spam-negreview.png
deleted file mode 100644
index f68eba3..0000000
--- a/docs/html/images/gp-policy-spam-negreview.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-policy-spam-reqrating.png b/docs/html/images/gp-policy-spam-reqrating.png
deleted file mode 100644
index 20e17c1..0000000
--- a/docs/html/images/gp-policy-spam-reqrating.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-premium-0.png b/docs/html/images/gp-premium-0.png
new file mode 100644
index 0000000..4bacc25
--- /dev/null
+++ b/docs/html/images/gp-premium-0.png
Binary files differ
diff --git a/docs/html/images/gp-rating-web.png b/docs/html/images/gp-rating-web.png
index 0885826..14582af 100644
--- a/docs/html/images/gp-rating-web.png
+++ b/docs/html/images/gp-rating-web.png
Binary files differ
diff --git a/docs/html/images/gp-sendto.png b/docs/html/images/gp-sendto.png
deleted file mode 100644
index 7409c14..0000000
--- a/docs/html/images/gp-sendto.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-start-button.png b/docs/html/images/gp-start-button.png
new file mode 100644
index 0000000..fa3d5e1
--- /dev/null
+++ b/docs/html/images/gp-start-button.png
Binary files differ
diff --git a/docs/html/images/gp-start-wallet-icon.png b/docs/html/images/gp-start-wallet-icon.png
new file mode 100644
index 0000000..3ecbcf6
--- /dev/null
+++ b/docs/html/images/gp-start-wallet-icon.png
Binary files differ
diff --git a/docs/html/images/gp-subs.png b/docs/html/images/gp-subs.png
deleted file mode 100644
index 9b3a7df..0000000
--- a/docs/html/images/gp-subs.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-subscription-0.jpg b/docs/html/images/gp-subscription-0.jpg
new file mode 100644
index 0000000..0c4b389
--- /dev/null
+++ b/docs/html/images/gp-subscription-0.jpg
Binary files differ
diff --git a/docs/html/images/gp-tab.png b/docs/html/images/gp-tab.png
deleted file mode 100644
index 4673d21..0000000
--- a/docs/html/images/gp-tab.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-tablet-quality-4.jpg b/docs/html/images/gp-tablet-quality-4.jpg
new file mode 100644
index 0000000..33dfcbd
--- /dev/null
+++ b/docs/html/images/gp-tablet-quality-4.jpg
Binary files differ
diff --git a/docs/html/images/gp-tablet-quality-5.jpg b/docs/html/images/gp-tablet-quality-5.jpg
new file mode 100644
index 0000000..668482a
--- /dev/null
+++ b/docs/html/images/gp-tablet-quality-5.jpg
Binary files differ
diff --git a/docs/html/images/gp-tablets-full-feature-set.png b/docs/html/images/gp-tablets-full-feature-set.png
new file mode 100644
index 0000000..fa04082
--- /dev/null
+++ b/docs/html/images/gp-tablets-full-feature-set.png
Binary files differ
diff --git a/docs/html/images/gp-top-new-paid.png b/docs/html/images/gp-top-new-paid.png
deleted file mode 100644
index d98d6ca..0000000
--- a/docs/html/images/gp-top-new-paid.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gp-your-user-0.jpg b/docs/html/images/gp-your-user-0.jpg
new file mode 100644
index 0000000..9286b54
--- /dev/null
+++ b/docs/html/images/gp-your-user-0.jpg
Binary files differ
diff --git a/docs/html/images/gp-your-user-2.jpg b/docs/html/images/gp-your-user-2.jpg
new file mode 100644
index 0000000..0f44e2a
--- /dev/null
+++ b/docs/html/images/gp-your-user-2.jpg
Binary files differ
diff --git a/docs/html/images/gpfe-developer.png b/docs/html/images/gpfe-developer.png
new file mode 100644
index 0000000..4b3251c
--- /dev/null
+++ b/docs/html/images/gpfe-developer.png
Binary files differ
diff --git a/docs/html/images/gpfe-educator.png b/docs/html/images/gpfe-educator.png
new file mode 100644
index 0000000..6e49a7fd
--- /dev/null
+++ b/docs/html/images/gpfe-educator.png
Binary files differ
diff --git a/docs/html/images/gpfe-start-0.jpg b/docs/html/images/gpfe-start-0.jpg
new file mode 100644
index 0000000..e97381d
--- /dev/null
+++ b/docs/html/images/gpfe-start-0.jpg
Binary files differ
diff --git a/docs/html/images/gpp-cat-feature280-photo.png b/docs/html/images/gpp-cat-feature280-photo.png
deleted file mode 100644
index ae2749b..0000000
--- a/docs/html/images/gpp-cat-feature280-photo.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gpp-cat-feature280-puzzle.png b/docs/html/images/gpp-cat-feature280-puzzle.png
deleted file mode 100644
index db203c6..0000000
--- a/docs/html/images/gpp-cat-feature280-puzzle.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/gpp-cat-feature280-sports.png b/docs/html/images/gpp-cat-feature280-sports.png
deleted file mode 100644
index dcd70aa..0000000
--- a/docs/html/images/gpp-cat-feature280-sports.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/mediarouter/media-route-provider-framework.png b/docs/html/images/mediarouter/media-route-provider-framework.png
new file mode 100644
index 0000000..60cc29a
--- /dev/null
+++ b/docs/html/images/mediarouter/media-route-provider-framework.png
Binary files differ
diff --git a/docs/html/images/play_dev.jpg b/docs/html/images/play_dev.jpg
new file mode 100644
index 0000000..6aae165
--- /dev/null
+++ b/docs/html/images/play_dev.jpg
Binary files differ
diff --git a/docs/html/images/play_dev.png b/docs/html/images/play_dev_sm.png
similarity index 100%
rename from docs/html/images/play_dev.png
rename to docs/html/images/play_dev_sm.png
Binary files differ
diff --git a/docs/html/images/plus.jpg b/docs/html/images/plus.jpg
new file mode 100644
index 0000000..652aa1a
--- /dev/null
+++ b/docs/html/images/plus.jpg
Binary files differ
diff --git a/docs/html/images/tools/as-android.png b/docs/html/images/tools/as-android.png
new file mode 100644
index 0000000..7808ed1
--- /dev/null
+++ b/docs/html/images/tools/as-android.png
Binary files differ
diff --git a/docs/html/images/tools/as-breakpointline.png b/docs/html/images/tools/as-breakpointline.png
new file mode 100644
index 0000000..9aea880
--- /dev/null
+++ b/docs/html/images/tools/as-breakpointline.png
Binary files differ
diff --git a/docs/html/images/tools/as-breakpointswindow.png b/docs/html/images/tools/as-breakpointswindow.png
new file mode 100644
index 0000000..a40b459
--- /dev/null
+++ b/docs/html/images/tools/as-breakpointswindow.png
Binary files differ
diff --git a/docs/html/images/tools/as-buildvariants.png b/docs/html/images/tools/as-buildvariants.png
new file mode 100644
index 0000000..a245163
--- /dev/null
+++ b/docs/html/images/tools/as-buildvariants.png
Binary files differ
diff --git a/docs/html/images/tools/as-capture.png b/docs/html/images/tools/as-capture.png
new file mode 100644
index 0000000..02f9f6f
--- /dev/null
+++ b/docs/html/images/tools/as-capture.png
Binary files differ
diff --git a/docs/html/images/tools/as-currentproc.png b/docs/html/images/tools/as-currentproc.png
new file mode 100644
index 0000000..4be8305
--- /dev/null
+++ b/docs/html/images/tools/as-currentproc.png
Binary files differ
diff --git a/docs/html/images/tools/as-ddmslog.png b/docs/html/images/tools/as-ddmslog.png
new file mode 100644
index 0000000..b53b8fe
--- /dev/null
+++ b/docs/html/images/tools/as-ddmslog.png
Binary files differ
diff --git a/docs/html/images/tools/as-debugbutton.png b/docs/html/images/tools/as-debugbutton.png
new file mode 100644
index 0000000..55e95d1
--- /dev/null
+++ b/docs/html/images/tools/as-debugbutton.png
Binary files differ
diff --git a/docs/html/images/tools/as-debugdevices.png b/docs/html/images/tools/as-debugdevices.png
new file mode 100644
index 0000000..09a9d0e
--- /dev/null
+++ b/docs/html/images/tools/as-debugdevices.png
Binary files differ
diff --git a/docs/html/images/tools/as-debugview.png b/docs/html/images/tools/as-debugview.png
new file mode 100644
index 0000000..0349147
--- /dev/null
+++ b/docs/html/images/tools/as-debugview.png
Binary files differ
diff --git a/docs/html/images/tools/as-debugwindowbutton.png b/docs/html/images/tools/as-debugwindowbutton.png
new file mode 100644
index 0000000..9016778
--- /dev/null
+++ b/docs/html/images/tools/as-debugwindowbutton.png
Binary files differ
diff --git a/docs/html/images/tools/as-demoflavordirs.png b/docs/html/images/tools/as-demoflavordirs.png
new file mode 100644
index 0000000..9d36a6d
--- /dev/null
+++ b/docs/html/images/tools/as-demoflavordirs.png
Binary files differ
diff --git a/docs/html/images/tools/as-devicecapture.png b/docs/html/images/tools/as-devicecapture.png
new file mode 100644
index 0000000..3236a89
--- /dev/null
+++ b/docs/html/images/tools/as-devicecapture.png
Binary files differ
diff --git a/docs/html/images/tools/as-evalexpbutton.png b/docs/html/images/tools/as-evalexpbutton.png
new file mode 100644
index 0000000..85b3c74
--- /dev/null
+++ b/docs/html/images/tools/as-evalexpbutton.png
Binary files differ
diff --git a/docs/html/images/tools/as-gradlebutton.png b/docs/html/images/tools/as-gradlebutton.png
new file mode 100644
index 0000000..091b935
--- /dev/null
+++ b/docs/html/images/tools/as-gradlebutton.png
Binary files differ
diff --git a/docs/html/images/tools/as-gradleconsole.png b/docs/html/images/tools/as-gradleconsole.png
new file mode 100644
index 0000000..c676c94
--- /dev/null
+++ b/docs/html/images/tools/as-gradleconsole.png
Binary files differ
diff --git a/docs/html/images/tools/as-gradlepanel.png b/docs/html/images/tools/as-gradlepanel.png
new file mode 100644
index 0000000..a409462
--- /dev/null
+++ b/docs/html/images/tools/as-gradlepanel.png
Binary files differ
diff --git a/docs/html/images/tools/as-gradlesync.png b/docs/html/images/tools/as-gradlesync.png
new file mode 100644
index 0000000..b312359
--- /dev/null
+++ b/docs/html/images/tools/as-gradlesync.png
Binary files differ
diff --git a/docs/html/images/tools/as-launchavdm.png b/docs/html/images/tools/as-launchavdm.png
new file mode 100644
index 0000000..bf15981
--- /dev/null
+++ b/docs/html/images/tools/as-launchavdm.png
Binary files differ
diff --git a/docs/html/images/tools/as-mainscreen.png b/docs/html/images/tools/as-mainscreen.png
new file mode 100644
index 0000000..da399d7
--- /dev/null
+++ b/docs/html/images/tools/as-mainscreen.png
Binary files differ
diff --git a/docs/html/images/tools/as-monitorbutton.png b/docs/html/images/tools/as-monitorbutton.png
new file mode 100644
index 0000000..6bdc3a5
--- /dev/null
+++ b/docs/html/images/tools/as-monitorbutton.png
Binary files differ
diff --git a/docs/html/images/tools/as-record.png b/docs/html/images/tools/as-record.png
new file mode 100644
index 0000000..5f7fa99
--- /dev/null
+++ b/docs/html/images/tools/as-record.png
Binary files differ
diff --git a/docs/html/images/tools/as-restart.png b/docs/html/images/tools/as-restart.png
new file mode 100644
index 0000000..12d2923
--- /dev/null
+++ b/docs/html/images/tools/as-restart.png
Binary files differ
diff --git a/docs/html/images/tools/as-resumeprogrambutton.png b/docs/html/images/tools/as-resumeprogrambutton.png
new file mode 100644
index 0000000..8096937
--- /dev/null
+++ b/docs/html/images/tools/as-resumeprogrambutton.png
Binary files differ
diff --git a/docs/html/images/tools/as-showdevview.png b/docs/html/images/tools/as-showdevview.png
new file mode 100644
index 0000000..602a6ad
--- /dev/null
+++ b/docs/html/images/tools/as-showdevview.png
Binary files differ
diff --git a/docs/html/images/tools/as-stepintobutton.png b/docs/html/images/tools/as-stepintobutton.png
new file mode 100644
index 0000000..569d4ed
--- /dev/null
+++ b/docs/html/images/tools/as-stepintobutton.png
Binary files differ
diff --git a/docs/html/images/tools/as-stepoutbutton.png b/docs/html/images/tools/as-stepoutbutton.png
new file mode 100644
index 0000000..ef8871f
--- /dev/null
+++ b/docs/html/images/tools/as-stepoutbutton.png
Binary files differ
diff --git a/docs/html/images/tools/as-stepoverbutton.png b/docs/html/images/tools/as-stepoverbutton.png
new file mode 100644
index 0000000..1c487df
--- /dev/null
+++ b/docs/html/images/tools/as-stepoverbutton.png
Binary files differ
diff --git a/docs/html/images/tools/as-variablesview.png b/docs/html/images/tools/as-variablesview.png
new file mode 100644
index 0000000..6a0b987
--- /dev/null
+++ b/docs/html/images/tools/as-variablesview.png
Binary files differ
diff --git a/docs/html/images/tools/as-varviewbutton.png b/docs/html/images/tools/as-varviewbutton.png
new file mode 100644
index 0000000..2ad4c58
--- /dev/null
+++ b/docs/html/images/tools/as-varviewbutton.png
Binary files differ
diff --git a/docs/html/images/tools/as-viewbreakbutton.png b/docs/html/images/tools/as-viewbreakbutton.png
new file mode 100644
index 0000000..22723d4
--- /dev/null
+++ b/docs/html/images/tools/as-viewbreakbutton.png
Binary files differ
diff --git a/docs/html/images/tools/studio_error_gradle5.png b/docs/html/images/tools/studio_error_gradle5.png
deleted file mode 100644
index 13de607..0000000
--- a/docs/html/images/tools/studio_error_gradle5.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/tools/studio_error_supportlib.png b/docs/html/images/tools/studio_error_supportlib.png
deleted file mode 100644
index 603b54c..0000000
--- a/docs/html/images/tools/studio_error_supportlib.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/images/video-Colopl.png b/docs/html/images/video-Colopl.png
deleted file mode 100644
index 0ee88c6..0000000
--- a/docs/html/images/video-Colopl.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/index.jd b/docs/html/index.jd
index baeaa5b..a4b0683 100644
--- a/docs/html/index.jd
+++ b/docs/html/index.jd
@@ -1,4 +1,5 @@
 fullpage=true
+page.viewport_width=970
 no_footer_links=true
 carousel=true
 excludeFromSuggestions=true
@@ -20,7 +21,7 @@
 
                 <li class="item carousel-home">
                   <div class="content-left col-10" style="width:580px;">
-                    <a href="{@docRoot}design/patterns/new.html">
+                    <a href="{@docRoot}wear/index.html">
                       <img src="{@docRoot}images/home/aw_dac.png" style="margin-top:50px" >
                     </a>
                   </div>
@@ -38,13 +39,12 @@
                       <script src="//ajax.googleapis.com/ajax/libs/swfobject/2.2/swfobject.js"></script>
                       <div style="box-shadow: 3px 10px 18px 1px #999;width:600px;height:336px">
                         <div id="ytapiplayer">
-                          <a href="http://www.youtube.com/watch?v=i2uvYI6blEE"><img width=600 
-                          src="https://i1.ytimg.com/vi/i2uvYI6blEE/maxresdefault.jpg"></a><!--You need Flash player 8+ and JavaScript enabled to view this video. -->
+                          <a href="http://www.youtube.com/watch?v=WWArLD6nqrk"><img width=600 src="{@docRoot}images/video-kiwi.jpg"></a><!--You need Flash player 8+ and JavaScript enabled to view this video. -->
                         </div>
                         <script type="text/javascript">
                             var params = { allowScriptAccess: "always" };
                             var atts = { id: "ytapiplayer" };
-                            swfobject.embedSWF("//www.youtube.com/v/i2uvYI6blEE?enablejsapi=1&playerapiid=ytplayer&version=3&HD=1;rel=0;showinfo=0;modestbranding;origin=developer.android.com;autohide=1",
+                            swfobject.embedSWF("//www.youtube.com/v/WWArLD6nqrk?enablejsapi=1&playerapiid=ytplayer&version=3&HD=1;rel=0;showinfo=0;modestbranding;origin=developer.android.com;autohide=1",
                               "ytapiplayer", "600", "336", "8", null, null, params, atts);
 
                             // Callback used to pause/resume carousel based on video state
@@ -73,9 +73,10 @@
                       </div>
                     </div>
                     <div class="content-right col-4">
-                    <h1 style="white-space:nowrap;line-height:1.2em;">Developer Story: <br />Box Inc.</h1>
-                    <p>Box is a cloud-based platform and app for users to share business information. See how they got over 5 million downloads by leveraging the flexibility in the Android platform.</p>
-                      <p><a href="{@docRoot}distribute/googleplay/spotlight/index.html" class="button">Watch more videos </a></p>
+                    <h1 style="white-space:nowrap;line-height:1.2em;">Developer Story: <br />Kiwi, Inc.</h1>
+                    <p>Game developer Kiwi has had five titles in the top 25 grossing on Google Play. Hear how Google Play
+                      has helped them double revenue every six months.</p>
+                      <p><a href="{@docRoot}distribute/stories/index.html" class="button">Watch more videos </a></p>
                     </div>
                 </li>
 
diff --git a/docs/html/jd_collections.js b/docs/html/jd_collections.js
new file mode 100644
index 0000000..8a4ac47
--- /dev/null
+++ b/docs/html/jd_collections.js
@@ -0,0 +1,697 @@
+var RESOURCE_COLLECTIONS = {
+  "launch/static": {
+    "title": "",
+    "resources": [
+      "http://www.youtube.com/watch?v=1RIz-cmTQB4",
+      "http://www.youtube.com/watch?v=MVBMWDzyHAI",
+      "http://android-developers.blogspot.com/2013/11/app-translation-service-now-available.html",
+      "http://android-developers.blogspot.com/2013/10/more-visibility-for-tablet-apps-in.html",
+      "http://android-developers.blogspot.com/2013/11/bring-your-apps-into-classroom-with.html",
+      "distribute/essentials/quality/tablets.html",
+      "distribute/users/build-buzz.html",
+      "distribute/monetize/premium.html",
+      "distribute/monetize/freemium.html",
+      "distribute/monetize/ads.html",
+      "distribute/essentials/best-practices/apps.html",
+      "distribute/essentials/best-practices/games.html",
+      "distribute/users/know-your-user.html",
+      "distribute/googleplay/developer-console.html"
+    ]
+  },
+  "distribute/gp/gplanding": {
+    "resources": [
+      "distribute/googleplay/about.html",
+      "distribute/googleplay/start.html",
+      "distribute/googleplay/developer-console.html"
+    ]
+  },
+  "distribute/gp/gpfelanding": {
+    "resources": [
+      "distribute/googleplay/edu/about.html",
+      "distribute/googleplay/edu/start.html",
+      "distribute/googleplay/edu/faq.html"
+    ]
+  },
+  "distribute/essentials": {
+    "resources": [
+      "distribute/essentials/quality/core.html",
+      "distribute/essentials/quality/tablets.html",
+      "distribute/essentials/gpfe-guidelines.html",
+      "distribute/essentials/optimizing-your-app.html",
+      "distribute/essentials/best-practices/apps.html",
+      "distribute/essentials/best-practices/games.html"
+    ]
+  },
+  "distribute/users": {
+    "title": "",
+    "resources": [
+      "distribute/users/know-your-user.html",
+      "distribute/users/your-listing.html",
+      "distribute/users/build-buzz.html",
+      "distribute/users/build-community.html",
+      "distribute/users/expand-to-new-markets.html"
+    ]
+  },
+  "distribute/engagelanding": {
+    "resources": [
+      "distribute/engage/widgets.html",
+      "distribute/engage/notifications.html",
+      "distribute/engage/gcm.html",
+      "distribute/engage/easy-signin.html",
+      "distribute/engage/deep-linking.html",
+      "distribute/engage/game-services.html",
+      "distribute/engage/app-updates.html",
+      "distribute/engage/community.html",
+      "distribute/engage/video.html"
+    ]
+  },
+  "distribute/monetize": {
+    "resources": [
+      "distribute/monetize/premium.html",
+      "distribute/monetize/freemium.html",
+      "distribute/monetize/subscriptions.html",
+      "distribute/monetize/ecommerce.html",
+      "distribute/monetize/ads.html",
+      "distribute/monetize/payments.html"
+    ]
+  },
+  "distribute/tools/checklists": {
+    "title": "",
+    "resources": [
+      "distribute/tools/launch-checklist.html",
+      "distribute/tools/localization-checklist.html"
+    ]
+  },
+  "distribute/tools/promote": {
+    "resources": [
+      "distribute/tools/promote/device-art.html",
+      "distribute/tools/promote/badges.html",
+      "distribute/tools/promote/linking.html"
+    ]
+  },
+  "distribute/tools/support": {
+    "title": "Google Play",
+    "resources": [
+      "https://support.google.com/googleplay/android-developer",
+      "https://support.google.com/googleplay/android-developer/answer/4430948",
+      "support.html"
+    ]
+  },
+  "distribute/tools/news": {
+    "title": "",
+    "resources": [
+      "http://android-developers.blogspot.com/",
+      "https://plus.google.com/+AndroidDevelopers/"
+    ]
+  },
+  "distribute/tools/more": {
+    "title": "Google Play",
+    "resources": [
+      "distribute/tools/promote/brand.html",
+      "distribute/tools/open-distribution.html",
+      "about/dashboards/index.html"
+    ]
+  },
+  "distribute/googleplay": {
+    "title": "Google Play",
+    "resources": [
+      "distribute/googleplay/developer-console.html",
+      "distribute/essentials/best-practices/apps.html",
+      "distribute/tools/launch-checklist.html",
+      "distribute/essentials/best-practices/games.html",
+    ]
+  },
+  "distribute/googleplay/gettingstarted": {
+    "title": "Get Started",
+    "resources": [
+      "distribute/googleplay/developer-console.html",
+      "https://support.google.com/googleplay/android-developer/answer/113468",
+      "https://support.google.com/googleplay/android-developer/answer/138294",
+      "https://support.google.com/googleplay/android-developer"
+    ]
+  },
+  "distribute/googleplay/developerconsole": {
+    "title": "Developer Console",
+    "resources": [
+      "google/play/billing/index.html",
+      "https://support.google.com/googleplay/android-developer/answer/138294"
+    ]
+  },
+  "distribute/googleplay/gpfe/highlight": {
+    "title": "About Google Play for Education",
+    "resources": [
+      "http://youtu.be/vzvpcEffvaE"
+    ]
+  },
+  "distribute/googleplay/gpfe/dev/about": {
+    "title": "About Google Play for Education / Developers",
+    "resources": [
+      "distribute/googleplay/edu/start.html",
+      "distribute/essentials/gpfe-guidelines.html",
+      "distribute/googleplay/edu/faq.html",
+      "distribute/essentials/quality/tablets.html"
+    ]
+  },
+  "distribute/googleplay/gpfe/dev": {
+    "title": "About Google Play for Education / Developers",
+    "resources": [
+      "distribute/googleplay/edu/about.html",
+      "distribute/essentials/gpfe-guidelines.html",
+      "distribute/essentials/quality/tablets.html",
+      "distribute/googleplay/developer-console.html",
+      "http://play.google.com/about/developer-distribution-agreement-addendum.html",
+    ]
+  },
+  "distribute/googleplay/aboutgpfe/educators/about": {
+    "title": "About Google Play for Education / Educators",
+    "resources": [
+      "http://www.google.com/edu/tablets/",
+      "http://www.youtube.com/watch?v=haEmsMo0f3w"
+    ]
+  },
+  "distribute/googleplay/aboutgpfe/educators": {
+    "title": "About Google Play for Education / Educators",
+    "resources": [
+      "http://www.google.com/edu/tablets/",
+      "http://youtu.be/vzvpcEffvaE"
+    ]
+  },
+  "distribute/googleplay/gettingstartedgpfe/educators": {
+    "title": "About Google Play for Education / Educators",
+    "resources": [
+      "http://www.google.com/edu/tablets/",
+      "http://youtu.be/vzvpcEffvaE"
+    ]
+  },
+  "distribute/essentials/eduessentials/developers": {
+    "title": "",
+    "resources": [
+      "distribute/googleplay/developer-console.html",
+      "distribute/googleplay/edu/start.html",
+      "distribute/googleplay/edu/faq.html"
+    ]
+  },
+  "distribute/essentials/eduessentials/educators": {
+    "title": "",
+    "resources": [
+      "http://www.google.com/edu/tablets/",
+      "distribute/essentials/quality/tablets.html",
+    ]
+  },
+  "distribute/essentials/optimizing": {
+    "title": "Optimizing Your App",
+    "resources": [
+      "design/index.html",
+      "training/articles/perf-anr.html",
+      "http://android-developers.blogspot.com/2013/10/improved-app-insight-by-linking-google.html"
+     ]
+  },
+  "distribute/users/knowyouruser": {
+    "title": "",
+    "resources": [
+      "distribute/essentials/optimizing-your-app.html",
+      "http://www.youtube.com/watch?v=RRelFvc6Czo",
+      "distribute/stories/localization.html"
+    ]
+  },
+  "distribute/users/buildbuzz": {
+    "title": "",
+    "resources": [
+      "distribute/tools/promote/badges.html",
+      "distribute/tools/promote/linking.html",
+      "distribute/tools/promote/device-art.html",
+      "http://plus.google.com/+GooglePlay"
+    ]
+  },
+  "distribute/users/createagreatlisting": {
+    "title": "",
+    "resources": [
+      "https://support.google.com/googleplay/android-developer/answer/1078870",
+      "http://android-developers.blogspot.com/2011/10/android-market-featured-image.html",
+      "distribute/tools/launch-checklist.html",
+      "http://android-developers.blogspot.com/2013/07/making-beautiful-android-app-icons.html",
+      "http://android-developers.blogspot.com/2012/12/localize-your-promotional-graphics-on.html",
+      "http://android-developers.blogspot.com/2013/10/making-your-app-content-more-accessible.html"
+    ]
+  },
+  "distribute/users/buildcommunity": {
+    "title": "",
+    "resources": [
+      "distribute/googleplay/developer-console.html",
+      "https://support.google.com/groups/answer/46601",
+      "https://support.google.com/plus/topic/2888488",
+      "http://www.youtube.com/yt/dev/"
+    ]
+  },
+  "distribute/toolsreference/bestpractices/apps": {
+    "title": "",
+    "resources": [
+      "distribute/googleplay/developer-console.html",
+      "http://android-developers.blogspot.com/"
+    ]
+  },
+  "distribute/toolsreference/bestpractices/games": {
+    "title": "",
+    "resources": [
+      "google/play-services/games.html",
+      "http://android-developers.blogspot.com/",
+      "distribute/googleplay/developer-console.html",
+      "http://www.youtube.com/watch?v=1RIz-cmTQB4"
+    ]
+  },
+  "distribute/essentials/corequalityguidelines/visualdesign": {
+    "title": "",
+    "resources": [
+      "design/index.html",
+      "design/patterns/navigation.html",
+      "design/patterns/actionbar.html",
+      "design/style/iconography.html",
+      "design/patterns/notifications.html"
+    ]
+  },
+  "distribute/essentials/corequalityguidelines/functionality": {
+    "title": "",
+    "resources": [
+      "http://android-developers.blogspot.com/2011/11/making-android-games-that-play-nice.html",
+      "guide/components/tasks-and-back-stack.html",
+      "training/basics/activity-lifecycle/recreating.html"
+    ]
+  },
+  "distribute/essentials/core/performance": {
+    "title": "",
+    "resources": [
+      "http://android-developers.blogspot.com/2010/12/new-gingerbread-api-strictmode.html",
+      "training/articles/perf-anr.html",
+      "http://android-developers.blogspot.com/2010/07/multithreading-for-performance.html"
+    ]
+  },
+  "distribute/essentials/core/play": {
+    "title": "",
+    "resources": [
+      "distribute/tools/launch-checklist.html",
+      "http://play.google.com/about/developer-content-policy.html",
+      "https://support.google.com/googleplay/android-developer/answer/188189",
+      "https://support.google.com/googleplay/android-developer/answer/1078870",
+      "http://android-developers.blogspot.com/2011/10/android-market-featured-image.html",
+      "https://support.google.com/googleplay/android-developer/answer/113477"
+    ]
+  },
+  "distribute/essentials/tabletguidelines/optimize": {
+    "title": "",
+    "resources": [
+      "design/style/metrics-grids.html",
+      "design/style/devices-displays.html",
+      "guide/practices/screens_support.html",
+      //"guide/practices/screens_support.html#ConfigurationExamples",
+    ]
+  },
+  "distribute/essentials/tabletguidelines/extrascreen": {
+    "title": "",
+    "resources": [
+      "design/patterns/multi-pane-layouts.html",
+      "training/design-navigation/multiple-sizes.html",
+      "training/multiscreen/index.html",
+    ]
+  },
+  "distribute/essentials/tabletguidelines/assets": {
+    "title": "",
+    "resources": [
+      "design/style/iconography.html",
+      "guide/topics/resources/providing-resources.html",
+      "guide/practices/screens_support.html",
+      "training/basics/supporting-devices/screens.html"
+    ]
+  },
+  "distribute/essentials/tabletguidelines/fonts": {
+    "title": "",
+    "resources": [
+      "design/style/metrics-grids.html",
+      "design/style/typography.html",
+      "guide/practices/screens_support.html",
+      "training/multiscreen/screendensities.html"
+    ]
+  },
+  "distribute/essentials/tabletguidelines/widgets": {
+    "title": "",
+    "resources": [
+      "guide/topics/appwidgets/index.html#MetaData",
+      "guide/topics/appwidgets/index.html",
+      "design/patterns/widgets.html"
+    ]
+  },
+  "distribute/essentials/tabletguidelines/versions": {
+    "title": "",
+    "resources": [
+      "guide/topics/manifest/uses-sdk-element.html#ApiLevels",
+      "guide/topics/manifest/uses-sdk-element.html",
+      "training/basics/supporting-devices/platforms.html"
+    ]
+  },
+  "distribute/essentials/tabletguidelines/hardware": {
+    "title": "",
+    "resources": [
+      "guide/topics/manifest/uses-feature-element.html",
+      "guide/topics/manifest/uses-feature-element.html#testing"
+    ]
+  },
+ "distribute/essentials/tabletguidelines/tabletscreens": {
+    "title": "",
+    "resources": [
+      "guide/practices/screens_support.html#DeclaringScreenSizeSupport",
+      "guide/practices/screens_support.html"
+    ]
+  },
+  "distribute/essentials/tabletguidelines/showcase": {
+    "title": "",
+    "resources": [
+      "distribute/tools/launch-checklist.html",
+      "https://play.google.com/apps/publish/",
+      "distribute/tools/promote/badges.html",
+      "distribute/tools/promote/device-art.html"
+    ]
+  },
+  "distribute/essentials/tabletguidelines/googleplay": {
+    "title": "",
+    "resources": [
+      "http://android-developers.blogspot.com/2013/10/more-visibility-for-tablet-apps-in.html",
+      "google/play/filters.html"
+    ]
+  },
+  "distribute/essentials/tabletguidelines": {
+    "title": "",
+    "resources": [
+      "distribute/essentials/quality/core.html",
+      "http://android-developers.blogspot.com/2013/10/more-visibility-for-tablet-apps-in.html",
+      "distribute/tools/launch-checklist.html",
+      "distribute/tools/promote/device-art.html"
+    ]
+  },
+  "distribute/getusers/notifications": {
+    "title": "",
+    "resources": [
+      "design/patterns/notifications.html",
+      "distribute/engage/gcm.html",
+      "http://play.google.com/about/developer-content-policy.html"
+    ]
+  },
+  "distribute/engage/widgets": {
+    "title": "",
+    "resources": [
+      "design/patterns/widgets.html",
+      "guide/topics/appwidgets/index.html"
+    ]
+  },
+  "distribute/getusers/expandnewmarkets": {
+    "title": "",
+    "resources": [
+      "distribute/tools/localization-checklist.html",
+      "https://support.google.com/googleplay/android-developer/table/3541286",
+      "distribute/stories/localization.html",
+      "distribute/tools/promote/badges.html",
+      "distribute/tools/promote/device-art.html",
+      "http://www.youtube.com/watch?v=SkHHPf3EdzE"
+    ]
+  },
+  "distribute/engage/gcm": {
+    "title": "",
+    "resources": [
+      "google/gcm/index.html",
+      "http://developer.chrome.com/apps/cloudMessagingV2",
+      "http://www.youtube.com/watch?v=y76rjidm8cU"
+    ]
+  },
+  "distribute/engage/googleplaygames": {
+    "title": "",
+    "resources": [
+      "google/play-services/games.html",
+      "distribute/essentials/best-practices/games.html"
+    ]
+  },
+  "distribute/engage/gplus": {
+    "title": "",
+    "resources": [
+      "google/play-services/plus.html",
+      "google/play-services/games.html",
+      "https://developers.google.com/+/mobile/android/share/interactive-post",
+      "https://developers.google.com/+/mobile/android/share/deep-link"
+    ]
+  },
+  "distribute/engage/community": {
+    "title": "",
+    "resources": [
+      "distribute/users/build-community.html",
+      "distribute/engage/video.html"
+    ]
+  },
+  "distribute/engage/deeplinks": {
+    "title": "",
+    "resources": [
+      "distribute/engage/easy-signin.html",
+      "https://developers.google.com/app-indexing/",
+      "https://developers.google.com/+/mobile/android/share/interactive-post"
+    ]
+  },
+  "distribute/engage/appupdates": {
+    "title": "",
+    "resources": [
+      "distribute/essentials/optimizing-your-app.html",
+      "distribute/tools/launch-checklist.html",
+      "distribute/googleplay/developer-console.html",
+      "design/patterns/notifications.html"
+    ]
+  },
+  "distribute/engage/video/more": {
+    "title": "",
+    "resources": [
+      "http://www.youtube.com/yt/dev/",
+      "distribute/essentials/best-practices/games.html",
+      "http://www.youtube.com/watch?v=RRelFvc6Czo"
+    ]
+  },
+  "distribute/engage/community": {
+    "title": "",
+    "resources": [
+      "distribute/users/build-community.html",
+      "distribute/engage/video.html"
+    ]
+  },
+  "distribute/engage/kiwi": {
+    "title": "",
+    "resources": [
+      "http://www.youtube.com/watch?v=WWArLD6nqrk"
+    ]
+  },
+  "distribute/toolsreference/gpfefaq": {
+    "title": "",
+    "resources": [
+      "http://www.google.com/edu/tablets/",
+      "distribute/googleplay/edu/start.html",
+      "http://play.google.com/about/developer-distribution-agreement-addendum.html",
+      "distribute/essentials/quality/core.html",
+      "distribute/essentials/quality/tablets.html"
+    ]
+  },
+  "distribute/toolsreference/localizationchecklist/identifylocales": {
+    "title": "",
+    "resources": [
+      "https://support.google.com/googleplay/android-developer/answer/138294"
+    ]
+  },
+  "distribute/tools/loc/designforloc": {
+    "title": "",
+    "resources": [
+      "http://android-developers.blogspot.com/2013/03/native-rtl-support-in-android-42.html",
+      "guide/topics/resources/string-resource.html#Plurals",
+      "guide/topics/resources/string-resource.html",
+      "reference/java/util/Locale.html"
+    ]
+  },
+  "distribute/toolsreference/localizationchecklist/managestrings": {
+    "title": "",
+    "resources": [
+      "guide/topics/resources/string-resource.html",
+      "design/style/writing.html",
+      "http://en.wikipedia.org/wiki/XLIFF"
+    ]
+  },
+  "distribute/toolsreference/localizationchecklist/translatestrings": {
+    "title": "",
+    "resources": [
+      "distribute/stories/localization.html",
+    ]
+  },
+  "distribute/toolsreference/localizationchecklist/preplaunch": {
+    "title": "",
+    "resources": [
+      "distribute/tools/promote/badges.html",
+      "distribute/tools/promote/device-art.html"
+    ]
+  },
+  "distribute/toolsreference/localizationchecklist/supportlaunch": {
+    "title": "",
+    "resources": [
+      "distribute/tools/launch-checklist.html",
+    ]
+  },
+  "distribute/toolsreference/launchchecklist/understanding": {
+    "title": "",
+    "resources": [
+      "tools/publishing/publishing_overview.html",
+      "tools/publishing/preparing.html"
+    ]
+  },
+  "distribute/toolsreference/launchchecklist/policies": {
+    "title": "",
+    "resources": [
+      "https://support.google.com/googleplay/android-developer/answer/4430948",
+      "https://support.google.com/googleplay/android-developer/topic/2364761",
+      "https://support.google.com/googleplay/android-developer"
+    ]
+  },
+  "distribute/toolsreference/launchchecklist/quality": {
+    "title": "",
+    "resources": [
+      "distribute/essentials/quality/core.html",
+      "distribute/essentials/quality/tablets.html",
+      "distribute/essentials/gpfe-guidelines.html"
+    ]
+  },
+  "distribute/toolsreference/launchchecklist/rating": {
+    "title": "",
+    "resources": [
+      "https://support.google.com/googleplay/android-developer/answer/188189",
+    ]
+  },
+  "distribute/toolsreference/launchchecklist/country": {
+    "title": "",
+    "resources": [
+      "https://support.google.com/googleplay/android-developer/answer/138294"
+    ]
+  },
+  "distribute/toolsreference/launchchecklist/size": {
+    "title": "",
+    "resources": [
+      "google/play/expansion-files.html",
+      "tools/help/proguard.html"
+    ]
+  },
+  "distribute/toolsreference/launchchecklist/platform": {
+    "title": "",
+    "resources": [
+      "guide/practices/screens_support.html",
+      "about/dashboards/index.html",
+      "guide/topics/manifest/uses-sdk-element.html"
+    ]
+  },
+  "distribute/toolsreference/launchchecklist/price": {
+    "title": "",
+    "resources": [
+      "https://support.google.com/googleplay/android-developer/table/3541286",
+    ]
+  },
+  "distribute/toolsreference/launchchecklist/purchasemethod": {
+    "title": "",
+    "resources": [
+      "google/play/billing/index.html",
+      "google/play/billing/billing_subscriptions.html"
+    ]
+  },
+  "distribute/toolsreference/launchchecklist/setprice": {
+    "title": "",
+    "resources": [
+      "https://support.google.com/googleplay/android-developer/answer/1169947",
+      "https://support.google.com/googleplay/android-developer/answer/138412",
+      "https://support.google.com/googleplay/android-developer/answer/112622",
+      "https://support.google.com/googleplay/android-developer/answer/138000"
+    ]
+  },
+  "distribute/toolsreference/launchchecklist/localization": {
+    "title": "",
+    "resources": [
+      "distribute/tools/localization-checklist.html",
+      "guide/topics/resources/localization.html",
+    ]
+  },
+  "distribute/toolsreference/launchchecklist/graphics": {
+    "title": "",
+    "resources": [
+      "https://support.google.com/googleplay/android-developer/answer/1078870",
+      "http://android-developers.blogspot.com/2011/10/android-market-featured-image.html"
+    ]
+  },
+  "distribute/toolsreference/launchchecklist/productdetails": {
+    "title": "",
+    "resources": [
+      "https://support.google.com/googleplay/android-developer/answer/113475",
+      "https://support.google.com/googleplay/android-developer/answer/1078870"
+    ]
+  },
+  "distribute/toolsreference/launchchecklist/badges": {
+    "title": "",
+    "resources": [
+      "distribute/tools/promote/badges.html",
+      "distribute/tools/promote/linking.html"
+    ]
+  },
+  "distribute/toolsreference/launchchecklist/finalchecks": {
+    "title": "",
+    "resources": [
+      "http://play.google.com/about/developer-content-policy.html",
+      "https://support.google.com/googleplay/android-developer/answer/113476",
+      "support.html"
+    ]
+  },
+  "distribute/toolsreference/launchchecklist/afterlaunch": {
+    "title": "",
+    "resources": [
+      "https://support.google.com/googleplay/android-developer/answer/113477",
+      "https://support.google.com/googleplay/android-developer/answer/1153479",
+      "https://support.google.com/payments/answer/2741495",
+      "distribute/essentials/optimizing-your-app.html"
+    ]
+  },
+  "distribute/monetize/premium": {
+    "title": "",
+    "resources": [
+      "google/play/billing/index.html",
+      "https://support.google.com/googleplay/android-developer/answer/4407611"
+    ]
+  },  
+  "distribute/monetize/freemium": {
+    "title": "",
+    "resources": [
+      "google/play/billing/index.html",
+      "https://support.google.com/googleplay/android-developer/answer/4407611"
+    ]
+  },
+  "distribute/monetize/subscriptions": {
+    "title": "",
+    "resources": [
+      "google/play/billing/billing_subscriptions.html",
+      "https://support.google.com/googleplay/android-developer/answer/4407611"
+    ]
+  },
+  "distribute/monetize/ecommerce": {
+    "title": "",
+    "resources": [
+      "https://developers.google.com/wallet/instant-buy/",
+      "https://support.google.com/googleplay/android-developer/answer/4407611"
+    ]
+  },
+  "distribute/monetize/advertising": {
+    "title": "",
+    "resources": [
+      "http://www.google.com/ads/admob/#subid=us-en-et-dac",
+      "http://www.google.com/doubleclick/publishers/small-business/index.html",
+      "http://support.google.com/googleplay/android-developer/topic/2985714",
+      "training/monetization/ads-and-ux.html"
+    ]
+  },
+  "distribute/monetize/paymentmethods": {
+    "title": "",
+    "resources": [
+      "https://play.google.com/about/giftcards/",
+      "https://support.google.com/googleplay/answer/2651410"
+    ]
+  },
+}
diff --git a/docs/html/jd_extras.js b/docs/html/jd_extras.js
new file mode 100644
index 0000000..f26b747b
--- /dev/null
+++ b/docs/html/jd_extras.js
@@ -0,0 +1,1104 @@
+/* Metadata represendations of resources that are outside of the autogenerated
+   local resource lists, or that override local resource representations.
+
+   Resources listed here are referenced from sitemap sections and collections,
+   matched by url string if there is no resource existing in ALL_RESOURCES.
+
+   Currently, these articles can override only the generated resources
+   in DISTRIBUTE_RESOURCES. A representation defined here will not be applied
+   when a collection or section specifies a url that's not in DISTRIBUTE_RESOURCEs.
+   Also
+   So if a section url refers to a static doc that's
+   not in a distribute section, you need to create an item for
+   it in this file. Fix is to compare across
+   ALL_RESOURCES_BY_URL.  */
+
+DISTRIBUTE_RESOURCES = DISTRIBUTE_RESOURCES.concat([
+  {
+    "title":"Developer Registration",
+    "titleFriendly":"",
+    "summary":"Additional information about the registration process.",
+    "url":"https://support.google.com/googleplay/android-developer/answer/113468",
+    "group":"",
+    "keywords": [],
+    "tags": [],
+    "image":"images/play_dev.jpg",
+    "type":"google"
+  },
+  {
+    "title": "Google Play Distribution and Seller Countries",
+    "titleFriendly":"",
+    "summary": "List of countries and territories where you can distribute your apps in Google Play.",
+    "url":"https://support.google.com/googleplay/android-developer/answer/138294",
+    "group":"",
+    "keywords": [],
+    "tags": [],
+    "image":"images/play_dev.jpg",
+    "type":"google"
+  },
+  {
+    "title":"Google Play Content Policies",
+    "titleFriendly":"",
+    "summary":"Details on policies relating to your developer account and app distribution is governed.",
+    "url":"https://support.google.com/googleplay/android-developer/topic/3453577",
+    "group":"",
+    "keywords": [],
+    "tags": ["#developersupport"],
+    "image":"images/play_dev.jpg",
+    "type":"google"
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": ["#developersupport #termsandpolicies"],
+    "url": "https://support.google.com/googleplay/android-developer/answer/4407611",
+    "timestamp": 1194884220000,
+    "image": 'images/play_dev.jpg',
+    "title": "Google Play Terms and Policies",
+    "summary": "Developer terms and policies that apply when you distribute apps in Google Play.",
+    "keywords": [],
+    "type": "distribute",
+    "titleFriendly": ""
+  },
+  {
+    "title":"Google Play Policy Center",
+    "titleFriendly":"",
+    "summary":"A central resource for you to learn about Google Play policies and guidelines.",
+    "url":"https://support.google.com/googleplay/android-developer/answer/4430948",
+    "group":"",
+    "keywords": [],
+    "tags": [],
+    "image":"http://storage.googleapis.com/support-kms-prod/SNP_712EA2784949DDF085C46E3BE7B1DC618A09_4389397_en_v0",
+    "type":"google"
+  },
+  {
+    "title":"Developer Help Center",
+    "titleFriendly":"",
+    "summary":"Complete details on getting started, publishing, troubleshooting, and more.",
+    "url":"https://support.google.com/googleplay/android-developer",
+    "group":"",
+    "keywords": [],
+    "tags": [],
+    "image":"images/play_dev.jpg",
+    "type":"google"
+  },
+  {
+    "title":"Google for Education",
+    "titleFriendly":"",
+    "summary":"Find out more about how Google can support your work with apps and tablets.",
+    "url":"http://www.google.com/edu/tablets/",
+    "group":"",
+    "keywords": [],
+    "tags": [],
+    "image":"distribute/images/gp-edu-apps-image.jpg",
+    "type":"google"
+  },
+  {
+    "title":"Keeping Your App Responsive",
+    "titleFriendly":"",
+    "summary":"This document describes how the Android system determines whether an application is not responding and provides guidelines for ensuring that your application stays responsive.",
+    "url":"training/articles/perf-anr.html",
+    "group":"",
+    "keywords": [],
+    "tags": [],
+    "image":"",
+    "type":"google"
+  },
+  {
+    "title":"Google Play Game Services",
+    "titleFriendly":"",
+    "summary":"Tools to offer a better game experience.",
+    "url":"google/play-services/games.html",
+    "group":"",
+    "keywords": [],
+    "tags": [],
+    "image":"",
+    "type":"google"
+  },
+
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [
+      "versions", "blog", "googleplay"
+    ],
+    "url": "http://android-developers.blogspot.com/",
+    "timestamp": 1004884220000,
+    "image": "images/blog.jpg",
+    "title": "Android Developers Blog",
+    "summary": "Follow the latest news on Android design, development, and distribution.",
+    "keywords": [],
+    "type": "blog",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "http://android-developers.blogspot.com/2011/11/making-android-games-that-play-nice.html",
+    "timestamp": 1194884220000,
+    "image": null,
+    "title": "Making Android Apps that Play Nice",
+    "summary": "Audio lifecycle and expected audio behaviors for Android apps.",
+    "keywords": [],
+    "type": "blog",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "http://android-developers.blogspot.com/2010/07/multithreading-for-performance.html",
+    "timestamp": 1194884220000,
+    "image": null,
+    "title": "Multithreading for Performance",
+    "summary": "Ways to improve performance through multi-threading.",
+    "keywords": [],
+    "type": "blog",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "http://play.google.com/about/developer-content-policy.html",
+    "timestamp": 1194884220000,
+    "image": "images/play_dev.jpg",
+    "title": "Developer Program Policies",
+    "summary": "Guidelines acceptable content in Google Play. Please read and understand the policies before publishing.",
+    "keywords": [],
+    "type": "google",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "https://support.google.com/googleplay/android-developer/answer/188189",
+    "timestamp": 1194884220000,
+    "image": "images/play_dev.jpg",
+    "title": "Rating your application content for Google Play",
+    "summary": "How to choose the appropriate content ratings level for your apps.",
+    "keywords": [],
+    "type": "support",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "http://android-developers.blogspot.com/2011/10/android-market-featured-image.html",
+    "timestamp": 1194884220000,
+    "image": "images/play_dev.jpg",
+    "title": "Google Play Featured Image Guidelines",
+    "summary": "How to create attractive, effective Featured Images for your apps.",
+    "keywords": [],
+    "type": "support",
+    "titleFriendly": ""
+  },
+{
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "https://support.google.com/googleplay/android-developer/answer/113477",
+    "timestamp": 1194884220000,
+    "image": "images/play_dev.jpg",
+    "title": "Supporting your users",
+    "summary": "Options for supporting users.",
+    "keywords": [],
+    "type": "support",
+    "titleFriendly": ""
+  },   
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "guide/practices/screens_support.html#ConfigurationExamples",
+    "timestamp": 1194884220000,
+    "image": null,
+    "title": "Configuration examples",
+    "summary": "How to declare layouts and other resources for specific screen sizes.",
+    "keywords": [],
+    "type": "design",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "training/design-navigation/multiple-sizes.html",
+    "timestamp": 1194884220000,
+    "image": null,
+    "title": "Planning for Multiple Touchscreen Sizes",
+    "summary": "",
+    "keywords": [],
+    "type": "design",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "training/multiscreen/index.html",
+    "timestamp": 1194884220000,
+    "image": null,
+    "title": "Designing for Multiple Screens",
+    "summary": "Designing an intuitive, effective navigation for tablets and other devices.",
+    "keywords": [],
+    "type": "design",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "guide/topics/resources/providing-resources.html",
+    "timestamp": 1194884220000,
+    "image": null,
+    "title": "Providing Resources",
+    "summary": "Layouts and drawable resources for specific ranges of device screens.",
+    "keywords": [],
+    "type": "design",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "training/basics/supporting-devices/screens.html",
+    "timestamp": 1194884220000,
+    "image": null,
+    "title": "Supporting Different Screens",
+    "summary": "Optimizing the user experience for different screen sizes and densities.",
+    "keywords": [],
+    "type": "design",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "guide/topics/appwidgets/index.html#MetaData",
+    "timestamp": 1194884220000,
+    "image": null,
+    "title": "Adding the AppWidgetProviderInfo Metadata",
+    "summary": "How to set the height and width dimensions of a widget.",
+    "keywords": [],
+    "type": "design",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "guide/topics/manifest/uses-sdk-element.html#ApiLevels",
+    "timestamp": 1194884220000,
+    "image": null,
+    "title": "Android API Levels",
+    "summary": "Introduction to API levels and how they relate to compatibility.",
+    "keywords": [],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "guide/practices/screens_support.html#DeclaringScreenSizeSupport",
+    "timestamp": 1194884220000,
+    "image": null,
+    "title": "Declaring screen size support",
+    "summary": "How to declare support for screen sizes in your app\'s manifest.",
+    "keywords": [],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "guide/topics/manifest/uses-feature-element.html#testing",
+    "timestamp": 1194884220000,
+    "image": null,
+    "title": "Checking for hardware feature requirements",
+    "summary": "Determining an app’s hardware and software requirements.",
+    "keywords": [],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "https://play.google.com/apps/publish/",
+    "timestamp": 1194884220000,
+    "image": null,
+    "title": "Google Play Developer Console",
+    "summary": "The tools console for publishing your app.",
+    "keywords": [],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "http://youtu.be/SkHHPf3EdzE",
+    "timestamp": 1194884220000,
+    "image": "http://i1.ytimg.com/vi/SkHHPf3EdzE/maxresdefault.jpg",
+    "title": "Level Up Your Android Game",
+    "summary": "Learn how to take your game to the next level on Google Play.",
+    "keywords": [],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "https://developers.google.com/+/mobile/android/share/interactive-post",
+    "timestamp": 1194884220000,
+    "image": 'images/google/gps-googleplus.png',
+    "title": "Sharing interactive posts to Google+ from your Android app",
+    "summary": "Interactive posts provide an easy and prominent way to allow users to share your site or app with their friends and invite them to take a specific action.",
+    "keywords": ["Interactive", "Google+"],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "http://play.google.com/about/developer-distribution-agreement.html",
+    "timestamp": 1194884220000,
+    "image": "images/play_dev.jpg",
+    "title": "Developer Distribution Agreement",
+    "summary": "Terms for distributing and selling apps and in-app products in Google Play.",
+    "keywords": [],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "https://support.google.com/googleplay/android-developer/answer/113417",
+    "timestamp": 1194884220000,
+    "image": null,
+    "title": "Inappropriate content in comments and applications",
+    "summary": "More details on what content is appropriate.",
+    "keywords": [],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "https://support.google.com/legal/troubleshooter/1114905",
+    "timestamp": 1194884220000,
+    "image": null,
+    "title": "Removing content from Google",
+    "summary": "Find how how to request the removal of content that infringes on your trademark.",
+    "keywords": [],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "http://play.google.com/about/developer-distribution-agreement-addendum.html",
+    "timestamp": 1194884220000,
+    "image": "images/play_dev.jpg",
+    "title": "Google Play for Education Addendum",
+    "summary": "Review the education-specific requirements.",
+    "keywords": [],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "http://android-developers.blogspot.com/2013/03/native-rtl-support-in-android-42.html",
+    "timestamp": null,
+    "image": null,
+    "title": "Native RTL Support in Android 4.2",
+    "summary": "Blog post that explains how to support RTL in your UI.",
+    "keywords": [],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "guide/topics/resources/string-resource.html#Plurals",
+    "timestamp": 1194884220000,
+    "image": null,
+    "title": "Quantity Strings (Plurals)",
+    "summary": "How to work with string plurals according to rules of grammar in a given locale.",
+    "keywords": [],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "reference/java/util/Locale.html",
+    "timestamp": 1194884220000,
+    "image": null,
+    "title": "Locale",
+    "summary": "Determine what CLDR data or version of the Unicode spec a particular Android platform version uses.",
+    "keywords": [],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+    {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "guide/topics/resources/string-resource.html",
+    "timestamp": 1194884220000,
+    "image": null,
+    "title": "String Resources",
+    "summary": "Explains how to use string resources in your UI.",
+    "keywords": [],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "distribute/tools/localization-checklist.html#strings",
+    "timestamp": 1194884220000,
+    "image": null,
+    "title": "Manage strings for localization",
+    "summary": "Guidance on having your strings translation ready.",
+    "keywords": [],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "tools/publishing/publishing_overview.html",
+    "timestamp": 1194884220000,
+    "image": null,
+    "title": "General Publishing Overview",
+    "summary": "Start here for an overview of publishing options for Android apps.",
+    "keywords": [],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "tools/publishing/preparing.html",
+    "timestamp": 1194884220000,
+    "image": null,
+    "title": "Preparing for Release",
+    "summary": "Developer documentation on how to build the signed, release-ready APK. This process is the same for all Android apps.",
+    "keywords": [],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "distribute/googleplay/policies/index.html",
+    "timestamp": 1194884220000,
+    "image": "images/play_dev.jpg",
+    "title": "Google Play Policies and Guidelines",
+    "summary": "An overview of Google Play policies for spam, intellectual property, and ads, with examples of common problems.",
+    "keywords": [],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "https://support.google.com/googleplay/android-developer/topic/2364761",
+    "timestamp": 1194884220000,
+    "image": "images/play_dev.jpg",
+    "title": "Policy and Best Practices",
+    "summary": "Help Center document describing various content policies and processes.",
+    "keywords": [],
+    "type": "distribute",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "google/play/expansion-files.html",
+    "timestamp": 1194884220000,
+    "image": null,
+    "title": "APK Expansion Files",
+    "summary": "Developer documentation describing APK Expansion Files and how to support them in your app.",
+    "keywords": [],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "tools/help/proguard.html",
+    "timestamp": 1194884220000,
+    "image": null,
+    "title": "ProGuard",
+    "summary": "Developer documentation describing how to use ProGuard to shrink, optimize, and obfuscate your code prior to release.",
+    "keywords": [],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+  {
+    "title":"Dashboards",
+    "titleFriendly":"",
+    "summary":"This page provides information about the relative number of devices that share a certain characteristic, such as Android version or screen size. This information may help you prioritize efforts for supporting different devices by revealing which devices…",
+    "url":"about/dashboards/index.html",
+    "group":"",
+    "keywords": ["android","dashboard","platforms","versions"],
+    "tags": ["#ecosystem","#versions","#whatsnew"],
+    "image":"http://chart.googleapis.com/chart?chl=GL%201.1%20only%7CGL%202.0%7CGL%203.0&chf=bg%2Cs%2C00000000&chd=t%3A0.1%2C93.5%2C6.4&chco=c4df9b%2C6fad0c&chs=400x250&cht=p",
+    "lang":"en",
+    "type":"about"
+  }, 
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "https://developers.google.com/wallet/instant-buy/",
+    "timestamp": 1194884220000,
+    "image": "distribute/images/payment-method.jpg",
+    "title": "Google Wallet Instant Buy APIs",
+    "summary": "Developer documentation describing Instant Buy and how to support it in your apps.",
+    "keywords": [],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "https://support.google.com/googleplay/android-developer/answer/1169947",
+    "timestamp": 1194884220000,
+    "image": "images/play_dev.jpg",
+    "title": "Selling Apps in Multiple Currencies",
+    "summary": "Help Center document describing how pricing works in Google Play.",
+    "keywords": [],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "https://support.google.com/googleplay/android-developer/answer/138412",
+    "timestamp": 1194884220000,
+    "image": "images/play_dev.jpg",
+    "title": "Prices and supported currencies",
+    "summary": "Help Center document listing supported currencies for pricing your apps.",
+    "keywords": [],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "https://support.google.com/googleplay/android-developer/answer/112622",
+    "timestamp": 1194884220000,
+    "image": "images/play_dev.jpg",
+    "title": "Transaction Fees",
+    "summary": "Help Center document describing transaction fees for priced apps and in-app products.",
+    "keywords": [],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "https://support.google.com/googleplay/android-developer/answer/138000",
+    "timestamp": 1194884220000,
+    "image": "images/play_dev.jpg",
+    "title": "Specifying tax rates",
+    "summary": "Help Center document describing how to set tax rates for different countries.",
+    "keywords": [],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "guide/topics/resources/localization.html",
+    "timestamp": 1194884220000,
+    "image": "images/play_dev.jpg",
+    "title": "Localizing with Resources",
+    "summary": "Developer guide to localizing resources in your app.",
+    "keywords": [],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "https://support.google.com/googleplay/android-developer/answer/113475",
+    "timestamp": 1194884220000,
+    "image": "images/play_dev.jpg",
+    "title": "Category types",
+    "summary": "Help Center document listing available categories for apps.",
+    "keywords": [],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "https://support.google.com/googleplay/android-developer/answer/113476",
+    "timestamp": 1194884220000,
+    "image": "images/play_dev.jpg",
+    "title": "Updates",
+    "summary": "Requirements for app updates in Google Play.",
+    "keywords": [],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "https://support.google.com/googleplay/android-developer/answer/1153479",
+    "timestamp": 1194884220000,
+    "image": null,
+    "title": "In-app Billing",
+    "summary": "Help Center document describing how to correctly set up In-app Billing.",
+    "keywords": [],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [
+      "#gpfe",
+      "#googleplay"
+    ],
+    "url": "http://youtu.be/vzvpcEffvaE",
+    "timestamp": 1383243492000,
+    "image": "http://i1.ytimg.com/vi/vzvpcEffvaE/maxresdefault.jpg",
+    "title": "Introducing Google Play for Education",
+    "summary": "Google Play for Education is a destination where schools can find great, teacher-approved, educational apps and videos on Play Store. Teachers can filter content by subject matter, grade and other criteria. Bulk purchase and instant distribution let educators bring your apps directly to classrooms and schools.",
+    "keywords": [],
+    "type": "youtube",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [
+      "#engagement",
+    ],
+    "url": "http://www.youtube.com/yt/dev/",
+    "timestamp": 1383243492000,
+    "image": "http://www.youtube.com/yt/dev/media/images/yt-dev-home-hero.jpg",
+    "title": "YouTube for Developers",
+    "summary": "The YouTube APIs and Tools enable you to integrate YouTube's video content and functionality into your website, app, or device.",
+    "keywords": [],
+    "type": "youtube",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [
+      "#engagement",
+    ],
+    "url": "https://developers.google.com/app-indexing/",
+    "timestamp": 1383243492000,
+    "image": "https://developers.google.com/app-indexing/images/allthecooks_srp.png",
+    "title": "Sign Up for App Indexing",
+    "summary": "Google is working with app developers and webmasters to index the content of apps and relate them to websites. When relevant, Google Search results on Android will include deep links to apps.",
+    "keywords": [],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [
+      "#gcm",
+    ],
+    "url": "http://www.youtube.com/watch?v=y76rjidm8cU",
+    "timestamp": 1383243492000,
+    "image": "http://1.bp.blogspot.com/-IF-1-1kA0sg/UYwTidxdi3I/AAAAAAAAAEU/ellLeQ-E1vs/s800/google-io-lockup-2.png",
+    "title": "Google Cloud Messaging at I/O 2013",
+    "summary": "Google Cloud Messaging allows your services to efficiently send data to applications on Android devices. See what's new, and learn how to use GCM to make your apps more efficient.",
+    "keywords": ["gcm"],
+    "type": "youtube",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [
+      "#googleplus",
+    ],
+    "url": "https://developers.google.com/+/mobile/android/people",
+    "timestamp": 1383243492000,
+    "image": "images/google/gps-googleplus.png",
+    "title": "Sign Up for App Indexing",
+    "summary": "After you let users sign in with Google, you can access their age range, language, public profile information, and people that they have circled.",
+    "keywords": ["googleplus"],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [
+      "#gcm",
+    ],
+    "url": "http://developer.chrome.com/apps/cloudMessagingV2",
+    "timestamp": 1383243492000,
+    "image": "images/kk-chromium-icon.png",
+    "title": "Google Cloud Messaging for Chrome",
+    "summary": "Google Cloud Messaging for Chrome (GCM) is a service for signed-in Chrome users that helps developers send message data from servers to their Chrome apps and extensions.",
+    "keywords": ["gcm"],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [
+      "#sdkupdates"
+    ],
+    "url": "http://android-developers.blogspot.com/2013/07/making-beautiful-android-app-icons.html",
+    "timestamp": 1194884220000,
+    "image": null,
+    "title": "Make Beautiful Android App Icons",
+    "summary": "Follow these in-depth launcher icon tips on the Android Developers blog.",
+    "keywords": [],
+    "type": "blog",
+    "titleFriendly": ""
+  },
+     {
+    "lang": "en",
+    "group": "",
+    "tags": [
+      "#sdkupdates"
+    ],
+    "url": "http://android-developers.blogspot.com/2012/12/localize-your-promotional-graphics-on.html",
+    "timestamp": 1194884220000,
+    "image": null,
+    "title": "Localize Your Promotional Graphics",
+    "summary": "Learn how to capitalise on international audiences.",
+    "keywords": [],
+    "type": "blog",
+    "titleFriendly": ""
+  },
+   {
+    "lang": "en",
+    "group": "",
+    "tags": [
+      "#sdkupdates"
+    ],
+    "url": "http://android-developers.blogspot.com/2013/10/making-your-app-content-more-accessible.html",
+    "timestamp": 1194884220000,
+    "image": null,
+    "title": "Make your App Content more Accessible with App Linking",
+    "summary": "About using search and deep linking to get more users.",
+    "keywords": [],
+    "type": "blog",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "https://developers.google.com/+/mobile/android/share/interactive-post",
+    "timestamp": 1194884220000,
+    "image": 'images/google/gps-googleplus.png',
+    "title": "Sharing interactive posts to Google+ from your Android app",
+    "summary": "Interactive posts provide an easy and prominent way to allow users to share your site or app with their friends and invite them to take a specific action.",
+    "keywords": ["Interactive", "Google+"],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "https://support.google.com/googleplay/android-developer/answer/2528691",
+    "timestamp": 1194884220000,
+    "image": "images/play_dev.jpg",
+    "title": "How to add multiple user accounts to your Developer Console for testing and more.",
+    "summary": "",
+    "keywords": [],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "https://developers.google.com/+/mobile/android/share/deep-link",
+    "timestamp": 1194884220000,
+    "image": null,
+    "title": "Adding deep linking to Google+ posts shared from your Android app",
+    "summary": "",
+    "keywords": [],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "google/play/licensing/index.html",
+    "timestamp": 1194884220000,
+    "image": null,
+    "title": "Application Licensing",
+    "summary": "Information on the features of Google Play to protect your apps’ licences.",
+    "keywords": [],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "design/style/writing.html",
+    "timestamp": 1194884220000,
+    "image": null,
+    "title": "Writing Style",
+    "summary": "Android Design guidelines for voice and style in your UI.",
+    "keywords": [],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "http://en.wikipedia.org/wiki/XLIFF",
+    "timestamp": 1194884220000,
+    "image": null,
+    "title": "XML Localisation Interchange File Format (XLIFF)",
+    "summary": "Background information on XLIFF.",
+    "keywords": [],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+    {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "https://support.google.com/googleplay/android-developer/answer/1078870",
+    "timestamp": 1194884220000,
+    "image": "images/play_dev.jpg",
+    "title": "Graphic Assets for your Application",
+    "summary": "Details about the graphics you can add to your product listing.",
+    "keywords": [],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "https://support.google.com/payments/answer/2741495",
+    "timestamp": null,
+    "image": null,
+    "title": "Issuing Refunds",
+    "summary": "Help Center document describing how to issue refunds.",
+    "keywords": [],
+    "type": "guide",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": [],
+    "url": "http://android-developers.blogspot.com/2013/11/bring-your-apps-into-classroom-with.html",
+    "timestamp": null,
+    "image": "distribute/images/gp-edu-apps-image.jpg",
+    "title": "Google play for education",
+    "summary": " ",
+    "keywords": [],
+    "type": "distribute",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": ["localization", "pricing", "developer support"],
+    "url": "https://support.google.com/googleplay/android-developer/table/3541286",
+    "timestamp": null,
+    "image": "images/play_dev.jpg",
+    "title": "Supported locations for distributing your apps in Google Play",
+    "summary": "Countries and regions where you can distribute your app in Google Play.",
+    "keywords": [],
+    "type": "distribute",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": ["games", "localization", "quality"],
+    "url": "http://www.youtube.com/watch?v=SkHHPf3EdzE",
+    "timestamp": null,
+    "image": "https://developers.google.com/apps/images/io_2013/google-io-logo.png",
+    "title": "Level Up Your Android Game",
+    "summary": "Learn how to take your game to the next level in this Google I/O session.",
+    "keywords": [],
+    "type": "distribute",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": ["support"],
+    "url": "https://support.google.com/groups/answer/46601",
+    "timestamp": null,
+    "image": null,
+    "title": "Google Groups",
+    "summary": "Create a group for your community.",
+    "keywords": [],
+    "type": "distribute",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": ["support"],
+    "url": "https://support.google.com/plus/topic/2888488",
+    "timestamp": null,
+    "image": null,
+    "title": "Google+ Communities",
+    "summary": "Host a Google+ community for testers or users.",
+    "keywords": [],
+    "type": "distribute",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": ["monetize", "ads"],
+    "url": "http://www.google.com/ads/admob/#subid=us-en-et-dac",
+    "timestamp": null,
+    "image": "distribute/images/advertising.png",
+    "title": "AdMob for Android",
+    "summary": "Make money by connecting with over a million Google advertisers all over the world, so your revenue scales with your app.",
+    "keywords": ["ads"],
+    "type": "distribute",
+    "titleFriendly": ""
+  },
+
+  {
+    "lang": "en",
+    "group": "",
+    "tags": ["monetize", "ads"],
+    "url": "http://www.google.com/doubleclick/publishers/small-business/index.html",
+    "timestamp": null,
+    "image": "http://www.google.com/doubleclick/publishers/small-business/images/define_ad.png",
+    "title": "DoubleClick for Publishers",
+    "summary": "A free ad management solution that helps growing publishers sell, schedule, deliver, and measure all of their digital ad inventory.",
+    "keywords": ["ads"],
+    "type": "distribute",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": ["monetize", "ads"],
+    "url": "http://support.google.com/googleplay/android-developer/topic/2985714",
+    "timestamp": null,
+    "image": "http://storage.googleapis.com/support-kms-prod/SNP_712EA2784949DDF085C46E3BE7B1DC618A09_4389397_en_v0",
+    "title": "Policy Center: Ads",
+    "summary": "Introduction to ads and system interference policies in Google Play",
+    "keywords": ["ads"],
+    "type": "distribute",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": ["monetize", "giftcards"],
+    "url": "https://play.google.com/about/giftcards/",
+    "timestamp": null,
+    "image": "images/gp-balance.png",
+    "title": "Google Play Gift Cards",
+    "summary": "Buy Google Play gift cards online or at a variety of retail stores.",
+    "keywords": ["gift card"],
+    "type": "distribute",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": ["monetize", "paymentmethods"],
+    "url": "https://support.google.com/googleplay/answer/2651410",
+    "timestamp": null,
+    "image": "images/play_dev.jpg",
+    "title": "Google Play Accepted Payment Methods",
+    "summary": "Support details on the payment methods supported in Google Play.",
+    "keywords": ["gift card"],
+    "type": "distribute",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": ["plus", "social"],
+    "url": "https://plus.google.com/+AndroidDevelopers/",
+    "timestamp": null,
+    "image": "images/plus.jpg",
+    "title": "+Android Developers",
+    "summary": "Sharing news, ideas, and techniques for success.",
+    "keywords": ["+AndroidDevelopers"],
+    "type": "Google+",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": ["plus", "social"],
+    "url": "http://plus.google.com/+GooglePlay",
+    "timestamp": null,
+    "image": "https://lh4.googleusercontent.com/-IKezweZlcXI/AAAAAAAAAAI/AAAAAAABOvg/uK8Z0jekVE4/s120-c/photo.jpg",
+    "title": "+Google Play",
+    "summary": "News and discussion about Google Play, apps, and other content in Google+.",
+    "keywords": ["+GooglePlay"],
+    "type": "Google+",
+    "titleFriendly": ""
+  },
+  {
+    "lang": "en",
+    "group": "",
+    "tags": ["support", "android"],
+    "url": "support.html",
+    "timestamp": null,
+    "image": null,
+    "title": "Developer Support",
+    "summary": "Links to community and support resources for Android developers.",
+    "keywords": ["support"],
+    "type": "Google+",
+    "titleFriendly": ""
+  },
+]); 
\ No newline at end of file
diff --git a/docs/html/jd_tag_helpers.js b/docs/html/jd_tag_helpers.js
new file mode 100644
index 0000000..ca01386
--- /dev/null
+++ b/docs/html/jd_tag_helpers.js
@@ -0,0 +1,110 @@
+function mergeArrays() {
+  var arr = arguments[0] || [];
+  for (var i = 1; i < arguments.length; i++) {
+    arr = arr.concat(arguments[i]);
+  }
+  return arr;
+}
+
+var ALL_RESOURCES = mergeArrays(
+  DESIGN_RESOURCES,
+  DISTRIBUTE_RESOURCES,
+  GOOGLE_RESOURCES,
+  GUIDE_RESOURCES,
+  SAMPLES_RESOURCES,
+  TOOLS_RESOURCES,
+  TRAINING_RESOURCES,
+  YOUTUBE_RESOURCES,
+  BLOGGER_RESOURCES
+);
+
+for (var i = 0; i < ALL_RESOURCES.length; i++) {
+  ALL_RESOURCES[i].index = i;
+}
+
+function mergeMaps() {
+  var allRes = {};
+  var offset = 0;
+
+  for (var i = 0; i < arguments.length; i++) {
+    var r = arguments[i];
+    for (var tag in r.map) {
+      allRes[tag] = allRes[tag] || [];
+      allRes[tag] = allRes[tag].concat(r.map[tag].map(function(i){ return ALL_RESOURCES[i + offset]; }));
+    }
+    offset += r.arr.length;
+  }
+
+  return allRes;
+}
+
+function setFromArray(arr) {
+  arr = arr || [];
+  var set = {};
+  for (var i = 0; i < arr.length; i++) {
+    set[arr[i]] = true;
+  }
+  return set;
+}
+
+function buildResourceLookupMap(resourceDict) {
+  var map = {};
+  for (var key in resourceDict) {
+    var dictForKey = {};
+    var srcArr = resourceDict[key];
+    for (var i = 0; i < srcArr.length; i++) {
+      dictForKey[srcArr[i].index] = true;
+    }
+    map[key] = dictForKey;
+  }
+  return map;
+}
+
+// Type lookups
+
+var ALL_RESOURCES_BY_TYPE = {
+  'design': DESIGN_RESOURCES,
+  'distribute': DISTRIBUTE_RESOURCES,
+  'google': GOOGLE_RESOURCES,
+  'guide': GUIDE_RESOURCES,
+  'samples': SAMPLES_RESOURCES,
+  'tools': TOOLS_RESOURCES,
+  'training': TRAINING_RESOURCES,
+  'youtube': YOUTUBE_RESOURCES,
+  'blog': BLOGGER_RESOURCES
+};
+var IS_RESOURCE_OF_TYPE = buildResourceLookupMap(ALL_RESOURCES_BY_TYPE);
+
+// Tag lookups
+
+var ALL_RESOURCES_BY_TAG = mergeMaps(
+  {map:DESIGN_BY_TAG,arr:DESIGN_RESOURCES},
+  {map:DISTRIBUTE_BY_TAG,arr:DISTRIBUTE_RESOURCES},
+  {map:GOOGLE_BY_TAG,arr:GOOGLE_RESOURCES},
+  {map:GUIDE_BY_TAG,arr:GUIDE_RESOURCES},
+  {map:SAMPLES_BY_TAG,arr:SAMPLES_RESOURCES},
+  {map:TOOLS_BY_TAG,arr:TOOLS_RESOURCES},
+  {map:TRAINING_BY_TAG,arr:TRAINING_RESOURCES},
+  {map:YOUTUBE_BY_TAG,arr:YOUTUBE_RESOURCES},
+  {map:BLOGGER_BY_TAG,arr:BLOGGER_RESOURCES}
+);
+var IS_RESOURCE_TAGGED = buildResourceLookupMap(ALL_RESOURCES_BY_TAG);
+
+// URL and language lookups
+
+var ALL_RESOURCES_BY_URL = {};
+var ALL_RESOURCES_BY_LANG = {};
+
+for (var i = 0; i < ALL_RESOURCES.length; i++) {
+  var res = ALL_RESOURCES[i];
+  var lang = res.lang;
+  if (lang) {
+    ALL_RESOURCES_BY_LANG[lang] = ALL_RESOURCES_BY_LANG[lang] || [];
+    ALL_RESOURCES_BY_LANG[lang].push(res);
+  }
+  var url = res.url;
+  if (url) {
+    ALL_RESOURCES_BY_URL[url] = res;
+  }
+}
+var IS_RESOURCE_IN_LANG = buildResourceLookupMap(ALL_RESOURCES_BY_LANG);
\ No newline at end of file
diff --git a/docs/html/legal.jd b/docs/html/legal.jd
index aaa3c39..c6143da 100644
--- a/docs/html/legal.jd
+++ b/docs/html/legal.jd
@@ -1,4 +1,5 @@
 page.title=Legal Notice
+page.type=about
 fullpage=1
 @jd:body
 
@@ -39,7 +40,7 @@
 use of it must be attributed as such.</p>
 
 <p>For more information about Android brands, see the <a
-href="{@docRoot}distribute/googleplay/promote/brand.html">Brand Guidelines</a>.</p>
+href="{@docRoot}distribute/tools/promote/brand.html">Brand Guidelines</a>.</p>
 
 <p>All other trademarks are the property of their respective owners.</p>
 
diff --git a/docs/html/license.jd b/docs/html/license.jd
index b98c912..0f671e2 100644
--- a/docs/html/license.jd
+++ b/docs/html/license.jd
@@ -1,4 +1,5 @@
 page.title=Content License
+page.type=about
 fullpage=1
 excludeFromSuggestions=true
 @jd:body
@@ -68,7 +69,7 @@
 style="margin:0;padding:0 2px;vertical-align:baseline" /> stylized typeface logo) are not included
 in the license.
 Please see <a
-href="{@docRoot}distribute/googleplay/promote/brand.html">Brand Guidelines</a> for
+href="{@docRoot}distribute/tools/promote/brand.html">Brand Guidelines</a> for
 information about this usage. </li>
 
 <li>In some cases, a page may include content, such as an image, that is not 
diff --git a/docs/html/reference/android/preview/support/package-summary.html b/docs/html/reference/android/preview/support/package-summary.html
index d367f87..2f50871 100644
--- a/docs/html/reference/android/preview/support/package-summary.html
+++ b/docs/html/reference/android/preview/support/package-summary.html
@@ -82,13 +82,6 @@
 
 
 
-
-
-
-
-
-
-
 <html>
 <head>
 
@@ -101,13 +94,15 @@
 
 <!-- STYLESHEETS -->
 <link rel="stylesheet"
-href="http://fonts.googleapis.com/css?family=Roboto:light,regular,medium,thin,italic,mediumitalic,bold" title="roboto">
+href="//fonts.googleapis.com/css?family=Roboto+Condensed">
+<link rel="stylesheet" href="//fonts.googleapis.com/css?family=Roboto:light,regular,medium,thin,italic,mediumitalic,bold"
+  title="roboto">
 <link href="/assets/css/default.css" rel="stylesheet" type="text/css">
 
 
 
 <!-- JAVASCRIPT -->
-<script src="http://www.google.com/jsapi" type="text/javascript"></script>
+<script src="//www.google.com/jsapi" type="text/javascript"></script>
 <script src="/assets/js/android_3p-bundle.js" type="text/javascript"></script>
 <script type="text/javascript">
   var toRoot = "/";
@@ -131,7 +126,7 @@
 
 
 <body class="gc-documentation 
-  develop">
+  preview">
   <div id="doc-api-level" class="" style="display:none"></div>
   <a name="top"></a>
 
@@ -139,31 +134,30 @@
   
 <a name="top"></a>
 
-    <!-- Header -->
-    <div id="header">
-        <div class="wrap" id="header-wrap">
-          <div class="col-3 logo-wear">
-          <a href="/wear/index.html">
-            <img src="/wear/images/android-wear.png" height="16" alt="Android Wear" />
-          </a>
-          </div>
+<!-- Header -->
+<div id="header-wrapper">
+  <div id="header">
+    <div class="wrap" id="header-wrap">
+      <div class="col_3 logo wear-logo">
+        <a href="/wear/index.html">
+          <img src="/wear/images/android-wear.png" height="16" alt="Android Wear" />
+        </a>
+      </div>
+      <div class="col-8" style="margin:0"><h1 style="margin:1px 0 0 20px;padding:0;line-height:16px;
+color:#666;font-weight:100;font-size:24px;">Developer Preview</h1></div>
 
-
-	<div class="col-8" style="margin:0"><h1 style="margin:1px 0 0 20px;padding:0;line-height:16px;
-  color:#666;font-weight:100;font-size:24px;">Developer Preview</h1></div>
-            
-
-          <!-- New Search -->
-          <div class="menu-container">
-            <div class="moremenu">
-	        <div id="more-btn"></div>
-	    </div>
+      
+      
+<div class="menu-container">
+  <div class="moremenu">
+    <div id="more-btn"></div>
+  </div>
   <div class="morehover" id="moremenu">
     <div class="top"></div>
     <div class="mid">
       <div class="header">Links</div>
       <ul>
-        <li><a href="https://play.google.com/apps/publish/">Google Play Developer Console</a></li>
+        <li><a href="https://play.google.com/apps/publish/" target="_googleplay">Google Play Developer Console</a></li>
         <li><a href="http://android-developers.blogspot.com/">Android Developers Blog</a></li>
         <li><a href="/about/index.html">About Android</a></li>
       </ul>
@@ -173,16 +167,32 @@
         <li class="active"><a>Android Developers</a></li>
         <li><a href="http://source.android.com">Android Open Source Project</a></li>
       </ul>
-      
-      
-      
-      
 
-
+      
+      
+        <div class="header">Language</div>
+          <div id="language" class="locales">
+            <select name="language" onChange="changeLangPref(this.value, true)">
+                <option value="en">English</option>
+                <option value="es">Español</option>
+                <option value="ja">日本語</option>
+                <option value="ko">한국어</option>
+                <option value="ru">Русский</option>
+                <option value="zh-cn">中文 (中国)</option>
+                <option value="zh-tw">中文 (台灣)</option>
+            </select>
+          </div>
+        <script type="text/javascript">
+          <!--
+          loadLangPref();
+            //-->
+        </script>
+      
+      
       <br class="clearfix" />
-    </div><!-- end mid -->
+    </div><!-- end 'mid' -->
     <div class="bottom"></div>
-  </div><!-- end morehover -->
+  </div><!-- end 'moremenu' -->
 
   <div class="search" id="search-container">
     <div class="search-inner">
@@ -190,16 +200,16 @@
       <div class="left"></div>
       <form onsubmit="return submit_search()">
         <input id="search_autocomplete" type="text" value="" autocomplete="off" name="q"
-onfocus="search_focus_changed(this, true)" onblur="search_focus_changed(this, false)"
-onkeydown="return search_changed(event, true, '/')" 
-onkeyup="return search_changed(event, false, '/')" />
+          onfocus="search_focus_changed(this, true)" onblur="search_focus_changed(this, false)"
+          onkeydown="return search_changed(event, true, '/')"
+          onkeyup="return search_changed(event, false, '/')" />
       </form>
       <div class="right"></div>
-        <a class="close hide">close</a>
-        <div class="left"></div>
-        <div class="right"></div>
-    </div>
-  </div><!--  end search -->
+      <a class="close hide">close</a>
+      <div class="left"></div>
+      <div class="right"></div>
+    </div><!-- end search-inner -->
+  </div><!-- end search-container -->
 
   <div class="search_filtered_wrapper reference">
     <div class="suggest-card reference no-display">
@@ -228,30 +238,37 @@
       <ul class="search_filtered">
       </ul>
     </div>
-  </div><!-- end search_filtered_wrapper -->
-
   </div>
-  <!-- end menu_container -->
+</div><!-- end menu-container (search and menu widget) -->
 
 
-        </div><!-- end header-wrap -->
-    </div>
-    <!-- /Header -->
+    </div><!-- end header-wrap -->
+  </div><!-- /Header -->
 
 
   <div id="searchResults" class="wrap" style="display:none;">
           <h2 id="searchTitle">Results</h2>
           <div id="leftSearchControl" class="search-control">Loading...</div>
   </div>
+</div> <!--end header-wrapper -->
+
+<div id="sticky-header">
+  <div>
+    <a class="logo" href="#top"></a>
+    <a class="top" href="#top"></a>
+    <ul class="breadcrumb">
+      
+      <li class="current">Preview Notifications Reference</li>
+    </ul>
+  </div>
+</div>
 
   
 
-  
 
   <div class="wrap clearfix" id="body-content">
     <div class="col-4" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
       <div id="devdoc-nav" class="scroll-pane">
-<a class="totop" href="#top" data-g-event="left-nav-top">to top</a>
 
 <ul id="nav">
 
@@ -328,7 +345,7 @@
 
 </ul>
 
-        
+
 
       </div>
     </div> <!-- end side-nav -->
@@ -362,12 +379,6 @@
 
 
 
-
-  
-
-
-
-
     <h2>android.preview.support.v4.app</h2>
     <div class="jd-sumtable">
     
@@ -418,14 +429,6 @@
   
 
 
-
-
-
-
-
-
-
-
   
 
 
diff --git a/docs/html/reference/android/preview/support/v4/app/NotificationManagerCompat.html b/docs/html/reference/android/preview/support/v4/app/NotificationManagerCompat.html
index 6375d9a..8322ab2 100644
--- a/docs/html/reference/android/preview/support/v4/app/NotificationManagerCompat.html
+++ b/docs/html/reference/android/preview/support/v4/app/NotificationManagerCompat.html
@@ -82,13 +82,6 @@
 
 
 
-
-
-
-
-
-
-
 <html>
 <head>
 
@@ -101,13 +94,15 @@
 
 <!-- STYLESHEETS -->
 <link rel="stylesheet"
-href="http://fonts.googleapis.com/css?family=Roboto:light,regular,medium,thin,italic,mediumitalic,bold" title="roboto">
+href="//fonts.googleapis.com/css?family=Roboto+Condensed">
+<link rel="stylesheet" href="//fonts.googleapis.com/css?family=Roboto:light,regular,medium,thin,italic,mediumitalic,bold"
+  title="roboto">
 <link href="/assets/css/default.css" rel="stylesheet" type="text/css">
 
 
 
 <!-- JAVASCRIPT -->
-<script src="http://www.google.com/jsapi" type="text/javascript"></script>
+<script src="//www.google.com/jsapi" type="text/javascript"></script>
 <script src="/assets/js/android_3p-bundle.js" type="text/javascript"></script>
 <script type="text/javascript">
   var toRoot = "/";
@@ -130,7 +125,7 @@
 </head>
 
 <body class="gc-documentation 
-  develop" itemscope itemtype="http://schema.org/Article">
+  preview" itemscope itemtype="http://schema.org/Article">
   <div id="doc-api-level" class="" style="display:none"></div>
   <a name="top"></a>
 
@@ -138,31 +133,30 @@
   
 <a name="top"></a>
 
-    <!-- Header -->
-    <div id="header">
-        <div class="wrap" id="header-wrap">
-          <div class="col-3 logo-wear">
-          <a href="/wear/index.html">
-            <img src="/wear/images/android-wear.png" height="16" alt="Android Wear" />
-          </a>
-          </div>
+<!-- Header -->
+<div id="header-wrapper">
+  <div id="header">
+    <div class="wrap" id="header-wrap">
+      <div class="col_3 logo wear-logo">
+        <a href="/wear/index.html">
+          <img src="/wear/images/android-wear.png" height="16" alt="Android Wear" />
+        </a>
+      </div>
+      <div class="col-8" style="margin:0"><h1 style="margin:1px 0 0 20px;padding:0;line-height:16px;
+color:#666;font-weight:100;font-size:24px;">Developer Preview</h1></div>
 
-
-	<div class="col-8" style="margin:0"><h1 style="margin:1px 0 0 20px;padding:0;line-height:16px;
-  color:#666;font-weight:100;font-size:24px;">Developer Preview</h1></div>
-            
-
-          <!-- New Search -->
-          <div class="menu-container">
-            <div class="moremenu">
-	        <div id="more-btn"></div>
-	    </div>
+      
+      
+<div class="menu-container">
+  <div class="moremenu">
+    <div id="more-btn"></div>
+  </div>
   <div class="morehover" id="moremenu">
     <div class="top"></div>
     <div class="mid">
       <div class="header">Links</div>
       <ul>
-        <li><a href="https://play.google.com/apps/publish/">Google Play Developer Console</a></li>
+        <li><a href="https://play.google.com/apps/publish/" target="_googleplay">Google Play Developer Console</a></li>
         <li><a href="http://android-developers.blogspot.com/">Android Developers Blog</a></li>
         <li><a href="/about/index.html">About Android</a></li>
       </ul>
@@ -172,16 +166,32 @@
         <li class="active"><a>Android Developers</a></li>
         <li><a href="http://source.android.com">Android Open Source Project</a></li>
       </ul>
-      
-      
-      
-      
 
-
+      
+      
+        <div class="header">Language</div>
+          <div id="language" class="locales">
+            <select name="language" onChange="changeLangPref(this.value, true)">
+                <option value="en">English</option>
+                <option value="es">Español</option>
+                <option value="ja">日本語</option>
+                <option value="ko">한국어</option>
+                <option value="ru">Русский</option>
+                <option value="zh-cn">中文 (中国)</option>
+                <option value="zh-tw">中文 (台灣)</option>
+            </select>
+          </div>
+        <script type="text/javascript">
+          <!--
+          loadLangPref();
+            //-->
+        </script>
+      
+      
       <br class="clearfix" />
-    </div><!-- end mid -->
+    </div><!-- end 'mid' -->
     <div class="bottom"></div>
-  </div><!-- end morehover -->
+  </div><!-- end 'moremenu' -->
 
   <div class="search" id="search-container">
     <div class="search-inner">
@@ -189,16 +199,16 @@
       <div class="left"></div>
       <form onsubmit="return submit_search()">
         <input id="search_autocomplete" type="text" value="" autocomplete="off" name="q"
-onfocus="search_focus_changed(this, true)" onblur="search_focus_changed(this, false)"
-onkeydown="return search_changed(event, true, '/')" 
-onkeyup="return search_changed(event, false, '/')" />
+          onfocus="search_focus_changed(this, true)" onblur="search_focus_changed(this, false)"
+          onkeydown="return search_changed(event, true, '/')"
+          onkeyup="return search_changed(event, false, '/')" />
       </form>
       <div class="right"></div>
-        <a class="close hide">close</a>
-        <div class="left"></div>
-        <div class="right"></div>
-    </div>
-  </div><!--  end search -->
+      <a class="close hide">close</a>
+      <div class="left"></div>
+      <div class="right"></div>
+    </div><!-- end search-inner -->
+  </div><!-- end search-container -->
 
   <div class="search_filtered_wrapper reference">
     <div class="suggest-card reference no-display">
@@ -227,30 +237,37 @@
       <ul class="search_filtered">
       </ul>
     </div>
-  </div><!-- end search_filtered_wrapper -->
-
   </div>
-  <!-- end menu_container -->
+</div><!-- end menu-container (search and menu widget) -->
 
 
-        </div><!-- end header-wrap -->
-    </div>
-    <!-- /Header -->
+    </div><!-- end header-wrap -->
+  </div><!-- /Header -->
 
 
   <div id="searchResults" class="wrap" style="display:none;">
           <h2 id="searchTitle">Results</h2>
           <div id="leftSearchControl" class="search-control">Loading...</div>
   </div>
+</div> <!--end header-wrapper -->
+
+<div id="sticky-header">
+  <div>
+    <a class="logo" href="#top"></a>
+    <a class="top" href="#top"></a>
+    <ul class="breadcrumb">
+      
+      <li class="current">NotificationManagerCompat</li>
+    </ul>
+  </div>
+</div>
 
   
 
-  
 
   <div class="wrap clearfix" id="body-content">
     <div class="col-4" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
       <div id="devdoc-nav" class="scroll-pane">
-<a class="totop" href="#top" data-g-event="left-nav-top">to top</a>
 
 <ul id="nav">
 
@@ -327,7 +344,7 @@
 
 </ul>
 
-        
+
 
       </div>
     </div> <!-- end side-nav -->
@@ -340,6 +357,7 @@
 
 
 
+
 <div class="col-12"  id="doc-col">
 
 <div id="api-info-block">
diff --git a/docs/html/reference/android/preview/support/wearable/notifications/RemoteInput.Builder.html b/docs/html/reference/android/preview/support/wearable/notifications/RemoteInput.Builder.html
index 6fbf8b6..77807e4 100644
--- a/docs/html/reference/android/preview/support/wearable/notifications/RemoteInput.Builder.html
+++ b/docs/html/reference/android/preview/support/wearable/notifications/RemoteInput.Builder.html
@@ -82,13 +82,6 @@
 
 
 
-
-
-
-
-
-
-
 <html>
 <head>
 
@@ -101,13 +94,15 @@
 
 <!-- STYLESHEETS -->
 <link rel="stylesheet"
-href="http://fonts.googleapis.com/css?family=Roboto:light,regular,medium,thin,italic,mediumitalic,bold" title="roboto">
+href="//fonts.googleapis.com/css?family=Roboto+Condensed">
+<link rel="stylesheet" href="//fonts.googleapis.com/css?family=Roboto:light,regular,medium,thin,italic,mediumitalic,bold"
+  title="roboto">
 <link href="/assets/css/default.css" rel="stylesheet" type="text/css">
 
 
 
 <!-- JAVASCRIPT -->
-<script src="http://www.google.com/jsapi" type="text/javascript"></script>
+<script src="//www.google.com/jsapi" type="text/javascript"></script>
 <script src="/assets/js/android_3p-bundle.js" type="text/javascript"></script>
 <script type="text/javascript">
   var toRoot = "/";
@@ -130,7 +125,7 @@
 </head>
 
 <body class="gc-documentation 
-  develop" itemscope itemtype="http://schema.org/Article">
+  preview" itemscope itemtype="http://schema.org/Article">
   <div id="doc-api-level" class="" style="display:none"></div>
   <a name="top"></a>
 
@@ -138,31 +133,30 @@
   
 <a name="top"></a>
 
-    <!-- Header -->
-    <div id="header">
-        <div class="wrap" id="header-wrap">
-          <div class="col-3 logo-wear">
-          <a href="/wear/index.html">
-            <img src="/wear/images/android-wear.png" height="16" alt="Android Wear" />
-          </a>
-          </div>
+<!-- Header -->
+<div id="header-wrapper">
+  <div id="header">
+    <div class="wrap" id="header-wrap">
+      <div class="col_3 logo wear-logo">
+        <a href="/wear/index.html">
+          <img src="/wear/images/android-wear.png" height="16" alt="Android Wear" />
+        </a>
+      </div>
+      <div class="col-8" style="margin:0"><h1 style="margin:1px 0 0 20px;padding:0;line-height:16px;
+color:#666;font-weight:100;font-size:24px;">Developer Preview</h1></div>
 
-
-	<div class="col-8" style="margin:0"><h1 style="margin:1px 0 0 20px;padding:0;line-height:16px;
-  color:#666;font-weight:100;font-size:24px;">Developer Preview</h1></div>
-            
-
-          <!-- New Search -->
-          <div class="menu-container">
-            <div class="moremenu">
-	        <div id="more-btn"></div>
-	    </div>
+      
+      
+<div class="menu-container">
+  <div class="moremenu">
+    <div id="more-btn"></div>
+  </div>
   <div class="morehover" id="moremenu">
     <div class="top"></div>
     <div class="mid">
       <div class="header">Links</div>
       <ul>
-        <li><a href="https://play.google.com/apps/publish/">Google Play Developer Console</a></li>
+        <li><a href="https://play.google.com/apps/publish/" target="_googleplay">Google Play Developer Console</a></li>
         <li><a href="http://android-developers.blogspot.com/">Android Developers Blog</a></li>
         <li><a href="/about/index.html">About Android</a></li>
       </ul>
@@ -172,16 +166,32 @@
         <li class="active"><a>Android Developers</a></li>
         <li><a href="http://source.android.com">Android Open Source Project</a></li>
       </ul>
-      
-      
-      
-      
 
-
+      
+      
+        <div class="header">Language</div>
+          <div id="language" class="locales">
+            <select name="language" onChange="changeLangPref(this.value, true)">
+                <option value="en">English</option>
+                <option value="es">Español</option>
+                <option value="ja">日本語</option>
+                <option value="ko">한국어</option>
+                <option value="ru">Русский</option>
+                <option value="zh-cn">中文 (中国)</option>
+                <option value="zh-tw">中文 (台灣)</option>
+            </select>
+          </div>
+        <script type="text/javascript">
+          <!--
+          loadLangPref();
+            //-->
+        </script>
+      
+      
       <br class="clearfix" />
-    </div><!-- end mid -->
+    </div><!-- end 'mid' -->
     <div class="bottom"></div>
-  </div><!-- end morehover -->
+  </div><!-- end 'moremenu' -->
 
   <div class="search" id="search-container">
     <div class="search-inner">
@@ -189,16 +199,16 @@
       <div class="left"></div>
       <form onsubmit="return submit_search()">
         <input id="search_autocomplete" type="text" value="" autocomplete="off" name="q"
-onfocus="search_focus_changed(this, true)" onblur="search_focus_changed(this, false)"
-onkeydown="return search_changed(event, true, '/')" 
-onkeyup="return search_changed(event, false, '/')" />
+          onfocus="search_focus_changed(this, true)" onblur="search_focus_changed(this, false)"
+          onkeydown="return search_changed(event, true, '/')"
+          onkeyup="return search_changed(event, false, '/')" />
       </form>
       <div class="right"></div>
-        <a class="close hide">close</a>
-        <div class="left"></div>
-        <div class="right"></div>
-    </div>
-  </div><!--  end search -->
+      <a class="close hide">close</a>
+      <div class="left"></div>
+      <div class="right"></div>
+    </div><!-- end search-inner -->
+  </div><!-- end search-container -->
 
   <div class="search_filtered_wrapper reference">
     <div class="suggest-card reference no-display">
@@ -227,30 +237,37 @@
       <ul class="search_filtered">
       </ul>
     </div>
-  </div><!-- end search_filtered_wrapper -->
-
   </div>
-  <!-- end menu_container -->
+</div><!-- end menu-container (search and menu widget) -->
 
 
-        </div><!-- end header-wrap -->
-    </div>
-    <!-- /Header -->
+    </div><!-- end header-wrap -->
+  </div><!-- /Header -->
 
 
   <div id="searchResults" class="wrap" style="display:none;">
           <h2 id="searchTitle">Results</h2>
           <div id="leftSearchControl" class="search-control">Loading...</div>
   </div>
+</div> <!--end header-wrapper -->
+
+<div id="sticky-header">
+  <div>
+    <a class="logo" href="#top"></a>
+    <a class="top" href="#top"></a>
+    <ul class="breadcrumb">
+      
+      <li class="current">RemoteInput.Builder</li>
+    </ul>
+  </div>
+</div>
 
   
 
-  
 
   <div class="wrap clearfix" id="body-content">
     <div class="col-4" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
       <div id="devdoc-nav" class="scroll-pane">
-<a class="totop" href="#top" data-g-event="left-nav-top">to top</a>
 
 <ul id="nav">
 
@@ -327,7 +344,7 @@
 
 </ul>
 
-        
+
 
       </div>
     </div> <!-- end side-nav -->
@@ -340,6 +357,7 @@
 
 
 
+
 <div class="col-12"  id="doc-col">
 
 <div id="api-info-block">
diff --git a/docs/html/reference/android/preview/support/wearable/notifications/RemoteInput.html b/docs/html/reference/android/preview/support/wearable/notifications/RemoteInput.html
index 0e1cebe..43fd36e 100644
--- a/docs/html/reference/android/preview/support/wearable/notifications/RemoteInput.html
+++ b/docs/html/reference/android/preview/support/wearable/notifications/RemoteInput.html
@@ -82,13 +82,6 @@
 
 
 
-
-
-
-
-
-
-
 <html>
 <head>
 
@@ -101,13 +94,15 @@
 
 <!-- STYLESHEETS -->
 <link rel="stylesheet"
-href="http://fonts.googleapis.com/css?family=Roboto:light,regular,medium,thin,italic,mediumitalic,bold" title="roboto">
+href="//fonts.googleapis.com/css?family=Roboto+Condensed">
+<link rel="stylesheet" href="//fonts.googleapis.com/css?family=Roboto:light,regular,medium,thin,italic,mediumitalic,bold"
+  title="roboto">
 <link href="/assets/css/default.css" rel="stylesheet" type="text/css">
 
 
 
 <!-- JAVASCRIPT -->
-<script src="http://www.google.com/jsapi" type="text/javascript"></script>
+<script src="//www.google.com/jsapi" type="text/javascript"></script>
 <script src="/assets/js/android_3p-bundle.js" type="text/javascript"></script>
 <script type="text/javascript">
   var toRoot = "/";
@@ -130,7 +125,7 @@
 </head>
 
 <body class="gc-documentation 
-  develop" itemscope itemtype="http://schema.org/Article">
+  preview" itemscope itemtype="http://schema.org/Article">
   <div id="doc-api-level" class="" style="display:none"></div>
   <a name="top"></a>
 
@@ -138,31 +133,30 @@
   
 <a name="top"></a>
 
-    <!-- Header -->
-    <div id="header">
-        <div class="wrap" id="header-wrap">
-          <div class="col-3 logo-wear">
-          <a href="/wear/index.html">
-            <img src="/wear/images/android-wear.png" height="16" alt="Android Wear" />
-          </a>
-          </div>
+<!-- Header -->
+<div id="header-wrapper">
+  <div id="header">
+    <div class="wrap" id="header-wrap">
+      <div class="col_3 logo wear-logo">
+        <a href="/wear/index.html">
+          <img src="/wear/images/android-wear.png" height="16" alt="Android Wear" />
+        </a>
+      </div>
+      <div class="col-8" style="margin:0"><h1 style="margin:1px 0 0 20px;padding:0;line-height:16px;
+color:#666;font-weight:100;font-size:24px;">Developer Preview</h1></div>
 
-
-	<div class="col-8" style="margin:0"><h1 style="margin:1px 0 0 20px;padding:0;line-height:16px;
-  color:#666;font-weight:100;font-size:24px;">Developer Preview</h1></div>
-            
-
-          <!-- New Search -->
-          <div class="menu-container">
-            <div class="moremenu">
-	        <div id="more-btn"></div>
-	    </div>
+      
+      
+<div class="menu-container">
+  <div class="moremenu">
+    <div id="more-btn"></div>
+  </div>
   <div class="morehover" id="moremenu">
     <div class="top"></div>
     <div class="mid">
       <div class="header">Links</div>
       <ul>
-        <li><a href="https://play.google.com/apps/publish/">Google Play Developer Console</a></li>
+        <li><a href="https://play.google.com/apps/publish/" target="_googleplay">Google Play Developer Console</a></li>
         <li><a href="http://android-developers.blogspot.com/">Android Developers Blog</a></li>
         <li><a href="/about/index.html">About Android</a></li>
       </ul>
@@ -172,16 +166,32 @@
         <li class="active"><a>Android Developers</a></li>
         <li><a href="http://source.android.com">Android Open Source Project</a></li>
       </ul>
-      
-      
-      
-      
 
-
+      
+      
+        <div class="header">Language</div>
+          <div id="language" class="locales">
+            <select name="language" onChange="changeLangPref(this.value, true)">
+                <option value="en">English</option>
+                <option value="es">Español</option>
+                <option value="ja">日本語</option>
+                <option value="ko">한국어</option>
+                <option value="ru">Русский</option>
+                <option value="zh-cn">中文 (中国)</option>
+                <option value="zh-tw">中文 (台灣)</option>
+            </select>
+          </div>
+        <script type="text/javascript">
+          <!--
+          loadLangPref();
+            //-->
+        </script>
+      
+      
       <br class="clearfix" />
-    </div><!-- end mid -->
+    </div><!-- end 'mid' -->
     <div class="bottom"></div>
-  </div><!-- end morehover -->
+  </div><!-- end 'moremenu' -->
 
   <div class="search" id="search-container">
     <div class="search-inner">
@@ -189,16 +199,16 @@
       <div class="left"></div>
       <form onsubmit="return submit_search()">
         <input id="search_autocomplete" type="text" value="" autocomplete="off" name="q"
-onfocus="search_focus_changed(this, true)" onblur="search_focus_changed(this, false)"
-onkeydown="return search_changed(event, true, '/')" 
-onkeyup="return search_changed(event, false, '/')" />
+          onfocus="search_focus_changed(this, true)" onblur="search_focus_changed(this, false)"
+          onkeydown="return search_changed(event, true, '/')"
+          onkeyup="return search_changed(event, false, '/')" />
       </form>
       <div class="right"></div>
-        <a class="close hide">close</a>
-        <div class="left"></div>
-        <div class="right"></div>
-    </div>
-  </div><!--  end search -->
+      <a class="close hide">close</a>
+      <div class="left"></div>
+      <div class="right"></div>
+    </div><!-- end search-inner -->
+  </div><!-- end search-container -->
 
   <div class="search_filtered_wrapper reference">
     <div class="suggest-card reference no-display">
@@ -227,30 +237,37 @@
       <ul class="search_filtered">
       </ul>
     </div>
-  </div><!-- end search_filtered_wrapper -->
-
   </div>
-  <!-- end menu_container -->
+</div><!-- end menu-container (search and menu widget) -->
 
 
-        </div><!-- end header-wrap -->
-    </div>
-    <!-- /Header -->
+    </div><!-- end header-wrap -->
+  </div><!-- /Header -->
 
 
   <div id="searchResults" class="wrap" style="display:none;">
           <h2 id="searchTitle">Results</h2>
           <div id="leftSearchControl" class="search-control">Loading...</div>
   </div>
+</div> <!--end header-wrapper -->
+
+<div id="sticky-header">
+  <div>
+    <a class="logo" href="#top"></a>
+    <a class="top" href="#top"></a>
+    <ul class="breadcrumb">
+      
+      <li class="current">RemoteInput</li>
+    </ul>
+  </div>
+</div>
 
   
 
-  
 
   <div class="wrap clearfix" id="body-content">
     <div class="col-4" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
       <div id="devdoc-nav" class="scroll-pane">
-<a class="totop" href="#top" data-g-event="left-nav-top">to top</a>
 
 <ul id="nav">
 
@@ -327,7 +344,7 @@
 
 </ul>
 
-        
+
 
       </div>
     </div> <!-- end side-nav -->
@@ -340,6 +357,7 @@
 
 
 
+
 <div class="col-12"  id="doc-col">
 
 <div id="api-info-block">
diff --git a/docs/html/reference/android/preview/support/wearable/notifications/WearableNotifications.Action.Builder.html b/docs/html/reference/android/preview/support/wearable/notifications/WearableNotifications.Action.Builder.html
index f27d406..9592e27 100644
--- a/docs/html/reference/android/preview/support/wearable/notifications/WearableNotifications.Action.Builder.html
+++ b/docs/html/reference/android/preview/support/wearable/notifications/WearableNotifications.Action.Builder.html
@@ -82,13 +82,6 @@
 
 
 
-
-
-
-
-
-
-
 <html>
 <head>
 
@@ -101,13 +94,15 @@
 
 <!-- STYLESHEETS -->
 <link rel="stylesheet"
-href="http://fonts.googleapis.com/css?family=Roboto:light,regular,medium,thin,italic,mediumitalic,bold" title="roboto">
+href="//fonts.googleapis.com/css?family=Roboto+Condensed">
+<link rel="stylesheet" href="//fonts.googleapis.com/css?family=Roboto:light,regular,medium,thin,italic,mediumitalic,bold"
+  title="roboto">
 <link href="/assets/css/default.css" rel="stylesheet" type="text/css">
 
 
 
 <!-- JAVASCRIPT -->
-<script src="http://www.google.com/jsapi" type="text/javascript"></script>
+<script src="//www.google.com/jsapi" type="text/javascript"></script>
 <script src="/assets/js/android_3p-bundle.js" type="text/javascript"></script>
 <script type="text/javascript">
   var toRoot = "/";
@@ -130,7 +125,7 @@
 </head>
 
 <body class="gc-documentation 
-  develop" itemscope itemtype="http://schema.org/Article">
+  preview" itemscope itemtype="http://schema.org/Article">
   <div id="doc-api-level" class="" style="display:none"></div>
   <a name="top"></a>
 
@@ -138,31 +133,30 @@
   
 <a name="top"></a>
 
-    <!-- Header -->
-    <div id="header">
-        <div class="wrap" id="header-wrap">
-          <div class="col-3 logo-wear">
-          <a href="/wear/index.html">
-            <img src="/wear/images/android-wear.png" height="16" alt="Android Wear" />
-          </a>
-          </div>
+<!-- Header -->
+<div id="header-wrapper">
+  <div id="header">
+    <div class="wrap" id="header-wrap">
+      <div class="col_3 logo wear-logo">
+        <a href="/wear/index.html">
+          <img src="/wear/images/android-wear.png" height="16" alt="Android Wear" />
+        </a>
+      </div>
+      <div class="col-8" style="margin:0"><h1 style="margin:1px 0 0 20px;padding:0;line-height:16px;
+color:#666;font-weight:100;font-size:24px;">Developer Preview</h1></div>
 
-
-	<div class="col-8" style="margin:0"><h1 style="margin:1px 0 0 20px;padding:0;line-height:16px;
-  color:#666;font-weight:100;font-size:24px;">Developer Preview</h1></div>
-            
-
-          <!-- New Search -->
-          <div class="menu-container">
-            <div class="moremenu">
-	        <div id="more-btn"></div>
-	    </div>
+      
+      
+<div class="menu-container">
+  <div class="moremenu">
+    <div id="more-btn"></div>
+  </div>
   <div class="morehover" id="moremenu">
     <div class="top"></div>
     <div class="mid">
       <div class="header">Links</div>
       <ul>
-        <li><a href="https://play.google.com/apps/publish/">Google Play Developer Console</a></li>
+        <li><a href="https://play.google.com/apps/publish/" target="_googleplay">Google Play Developer Console</a></li>
         <li><a href="http://android-developers.blogspot.com/">Android Developers Blog</a></li>
         <li><a href="/about/index.html">About Android</a></li>
       </ul>
@@ -172,16 +166,32 @@
         <li class="active"><a>Android Developers</a></li>
         <li><a href="http://source.android.com">Android Open Source Project</a></li>
       </ul>
-      
-      
-      
-      
 
-
+      
+      
+        <div class="header">Language</div>
+          <div id="language" class="locales">
+            <select name="language" onChange="changeLangPref(this.value, true)">
+                <option value="en">English</option>
+                <option value="es">Español</option>
+                <option value="ja">日本語</option>
+                <option value="ko">한국어</option>
+                <option value="ru">Русский</option>
+                <option value="zh-cn">中文 (中国)</option>
+                <option value="zh-tw">中文 (台灣)</option>
+            </select>
+          </div>
+        <script type="text/javascript">
+          <!--
+          loadLangPref();
+            //-->
+        </script>
+      
+      
       <br class="clearfix" />
-    </div><!-- end mid -->
+    </div><!-- end 'mid' -->
     <div class="bottom"></div>
-  </div><!-- end morehover -->
+  </div><!-- end 'moremenu' -->
 
   <div class="search" id="search-container">
     <div class="search-inner">
@@ -189,16 +199,16 @@
       <div class="left"></div>
       <form onsubmit="return submit_search()">
         <input id="search_autocomplete" type="text" value="" autocomplete="off" name="q"
-onfocus="search_focus_changed(this, true)" onblur="search_focus_changed(this, false)"
-onkeydown="return search_changed(event, true, '/')" 
-onkeyup="return search_changed(event, false, '/')" />
+          onfocus="search_focus_changed(this, true)" onblur="search_focus_changed(this, false)"
+          onkeydown="return search_changed(event, true, '/')"
+          onkeyup="return search_changed(event, false, '/')" />
       </form>
       <div class="right"></div>
-        <a class="close hide">close</a>
-        <div class="left"></div>
-        <div class="right"></div>
-    </div>
-  </div><!--  end search -->
+      <a class="close hide">close</a>
+      <div class="left"></div>
+      <div class="right"></div>
+    </div><!-- end search-inner -->
+  </div><!-- end search-container -->
 
   <div class="search_filtered_wrapper reference">
     <div class="suggest-card reference no-display">
@@ -227,30 +237,37 @@
       <ul class="search_filtered">
       </ul>
     </div>
-  </div><!-- end search_filtered_wrapper -->
-
   </div>
-  <!-- end menu_container -->
+</div><!-- end menu-container (search and menu widget) -->
 
 
-        </div><!-- end header-wrap -->
-    </div>
-    <!-- /Header -->
+    </div><!-- end header-wrap -->
+  </div><!-- /Header -->
 
 
   <div id="searchResults" class="wrap" style="display:none;">
           <h2 id="searchTitle">Results</h2>
           <div id="leftSearchControl" class="search-control">Loading...</div>
   </div>
+</div> <!--end header-wrapper -->
+
+<div id="sticky-header">
+  <div>
+    <a class="logo" href="#top"></a>
+    <a class="top" href="#top"></a>
+    <ul class="breadcrumb">
+      
+      <li class="current">WearableNotifications.Action.Builder</li>
+    </ul>
+  </div>
+</div>
 
   
 
-  
 
   <div class="wrap clearfix" id="body-content">
     <div class="col-4" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
       <div id="devdoc-nav" class="scroll-pane">
-<a class="totop" href="#top" data-g-event="left-nav-top">to top</a>
 
 <ul id="nav">
 
@@ -327,7 +344,7 @@
 
 </ul>
 
-        
+
 
       </div>
     </div> <!-- end side-nav -->
@@ -340,6 +357,7 @@
 
 
 
+
 <div class="col-12"  id="doc-col">
 
 <div id="api-info-block">
diff --git a/docs/html/reference/android/preview/support/wearable/notifications/WearableNotifications.Action.html b/docs/html/reference/android/preview/support/wearable/notifications/WearableNotifications.Action.html
index ff9c904..8073fa8 100644
--- a/docs/html/reference/android/preview/support/wearable/notifications/WearableNotifications.Action.html
+++ b/docs/html/reference/android/preview/support/wearable/notifications/WearableNotifications.Action.html
@@ -82,13 +82,6 @@
 
 
 
-
-
-
-
-
-
-
 <html>
 <head>
 
@@ -101,13 +94,15 @@
 
 <!-- STYLESHEETS -->
 <link rel="stylesheet"
-href="http://fonts.googleapis.com/css?family=Roboto:light,regular,medium,thin,italic,mediumitalic,bold" title="roboto">
+href="//fonts.googleapis.com/css?family=Roboto+Condensed">
+<link rel="stylesheet" href="//fonts.googleapis.com/css?family=Roboto:light,regular,medium,thin,italic,mediumitalic,bold"
+  title="roboto">
 <link href="/assets/css/default.css" rel="stylesheet" type="text/css">
 
 
 
 <!-- JAVASCRIPT -->
-<script src="http://www.google.com/jsapi" type="text/javascript"></script>
+<script src="//www.google.com/jsapi" type="text/javascript"></script>
 <script src="/assets/js/android_3p-bundle.js" type="text/javascript"></script>
 <script type="text/javascript">
   var toRoot = "/";
@@ -130,7 +125,7 @@
 </head>
 
 <body class="gc-documentation 
-  develop" itemscope itemtype="http://schema.org/Article">
+  preview" itemscope itemtype="http://schema.org/Article">
   <div id="doc-api-level" class="" style="display:none"></div>
   <a name="top"></a>
 
@@ -138,31 +133,30 @@
   
 <a name="top"></a>
 
-    <!-- Header -->
-    <div id="header">
-        <div class="wrap" id="header-wrap">
-          <div class="col-3 logo-wear">
-          <a href="/wear/index.html">
-            <img src="/wear/images/android-wear.png" height="16" alt="Android Wear" />
-          </a>
-          </div>
+<!-- Header -->
+<div id="header-wrapper">
+  <div id="header">
+    <div class="wrap" id="header-wrap">
+      <div class="col_3 logo wear-logo">
+        <a href="/wear/index.html">
+          <img src="/wear/images/android-wear.png" height="16" alt="Android Wear" />
+        </a>
+      </div>
+      <div class="col-8" style="margin:0"><h1 style="margin:1px 0 0 20px;padding:0;line-height:16px;
+color:#666;font-weight:100;font-size:24px;">Developer Preview</h1></div>
 
-
-	<div class="col-8" style="margin:0"><h1 style="margin:1px 0 0 20px;padding:0;line-height:16px;
-  color:#666;font-weight:100;font-size:24px;">Developer Preview</h1></div>
-            
-
-          <!-- New Search -->
-          <div class="menu-container">
-            <div class="moremenu">
-	        <div id="more-btn"></div>
-	    </div>
+      
+      
+<div class="menu-container">
+  <div class="moremenu">
+    <div id="more-btn"></div>
+  </div>
   <div class="morehover" id="moremenu">
     <div class="top"></div>
     <div class="mid">
       <div class="header">Links</div>
       <ul>
-        <li><a href="https://play.google.com/apps/publish/">Google Play Developer Console</a></li>
+        <li><a href="https://play.google.com/apps/publish/" target="_googleplay">Google Play Developer Console</a></li>
         <li><a href="http://android-developers.blogspot.com/">Android Developers Blog</a></li>
         <li><a href="/about/index.html">About Android</a></li>
       </ul>
@@ -172,16 +166,32 @@
         <li class="active"><a>Android Developers</a></li>
         <li><a href="http://source.android.com">Android Open Source Project</a></li>
       </ul>
-      
-      
-      
-      
 
-
+      
+      
+        <div class="header">Language</div>
+          <div id="language" class="locales">
+            <select name="language" onChange="changeLangPref(this.value, true)">
+                <option value="en">English</option>
+                <option value="es">Español</option>
+                <option value="ja">日本語</option>
+                <option value="ko">한국어</option>
+                <option value="ru">Русский</option>
+                <option value="zh-cn">中文 (中国)</option>
+                <option value="zh-tw">中文 (台灣)</option>
+            </select>
+          </div>
+        <script type="text/javascript">
+          <!--
+          loadLangPref();
+            //-->
+        </script>
+      
+      
       <br class="clearfix" />
-    </div><!-- end mid -->
+    </div><!-- end 'mid' -->
     <div class="bottom"></div>
-  </div><!-- end morehover -->
+  </div><!-- end 'moremenu' -->
 
   <div class="search" id="search-container">
     <div class="search-inner">
@@ -189,16 +199,16 @@
       <div class="left"></div>
       <form onsubmit="return submit_search()">
         <input id="search_autocomplete" type="text" value="" autocomplete="off" name="q"
-onfocus="search_focus_changed(this, true)" onblur="search_focus_changed(this, false)"
-onkeydown="return search_changed(event, true, '/')" 
-onkeyup="return search_changed(event, false, '/')" />
+          onfocus="search_focus_changed(this, true)" onblur="search_focus_changed(this, false)"
+          onkeydown="return search_changed(event, true, '/')"
+          onkeyup="return search_changed(event, false, '/')" />
       </form>
       <div class="right"></div>
-        <a class="close hide">close</a>
-        <div class="left"></div>
-        <div class="right"></div>
-    </div>
-  </div><!--  end search -->
+      <a class="close hide">close</a>
+      <div class="left"></div>
+      <div class="right"></div>
+    </div><!-- end search-inner -->
+  </div><!-- end search-container -->
 
   <div class="search_filtered_wrapper reference">
     <div class="suggest-card reference no-display">
@@ -227,30 +237,37 @@
       <ul class="search_filtered">
       </ul>
     </div>
-  </div><!-- end search_filtered_wrapper -->
-
   </div>
-  <!-- end menu_container -->
+</div><!-- end menu-container (search and menu widget) -->
 
 
-        </div><!-- end header-wrap -->
-    </div>
-    <!-- /Header -->
+    </div><!-- end header-wrap -->
+  </div><!-- /Header -->
 
 
   <div id="searchResults" class="wrap" style="display:none;">
           <h2 id="searchTitle">Results</h2>
           <div id="leftSearchControl" class="search-control">Loading...</div>
   </div>
+</div> <!--end header-wrapper -->
+
+<div id="sticky-header">
+  <div>
+    <a class="logo" href="#top"></a>
+    <a class="top" href="#top"></a>
+    <ul class="breadcrumb">
+      
+      <li class="current">WearableNotifications.Action</li>
+    </ul>
+  </div>
+</div>
 
   
 
-  
 
   <div class="wrap clearfix" id="body-content">
     <div class="col-4" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
       <div id="devdoc-nav" class="scroll-pane">
-<a class="totop" href="#top" data-g-event="left-nav-top">to top</a>
 
 <ul id="nav">
 
@@ -327,7 +344,7 @@
 
 </ul>
 
-        
+
 
       </div>
     </div> <!-- end side-nav -->
@@ -340,6 +357,7 @@
 
 
 
+
 <div class="col-12"  id="doc-col">
 
 <div id="api-info-block">
diff --git a/docs/html/reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html b/docs/html/reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html
index d6ec260..15d3303 100644
--- a/docs/html/reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html
+++ b/docs/html/reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html
@@ -82,13 +82,6 @@
 
 
 
-
-
-
-
-
-
-
 <html>
 <head>
 
@@ -101,13 +94,15 @@
 
 <!-- STYLESHEETS -->
 <link rel="stylesheet"
-href="http://fonts.googleapis.com/css?family=Roboto:light,regular,medium,thin,italic,mediumitalic,bold" title="roboto">
+href="//fonts.googleapis.com/css?family=Roboto+Condensed">
+<link rel="stylesheet" href="//fonts.googleapis.com/css?family=Roboto:light,regular,medium,thin,italic,mediumitalic,bold"
+  title="roboto">
 <link href="/assets/css/default.css" rel="stylesheet" type="text/css">
 
 
 
 <!-- JAVASCRIPT -->
-<script src="http://www.google.com/jsapi" type="text/javascript"></script>
+<script src="//www.google.com/jsapi" type="text/javascript"></script>
 <script src="/assets/js/android_3p-bundle.js" type="text/javascript"></script>
 <script type="text/javascript">
   var toRoot = "/";
@@ -130,7 +125,7 @@
 </head>
 
 <body class="gc-documentation 
-  develop" itemscope itemtype="http://schema.org/Article">
+  preview" itemscope itemtype="http://schema.org/Article">
   <div id="doc-api-level" class="" style="display:none"></div>
   <a name="top"></a>
 
@@ -138,31 +133,30 @@
   
 <a name="top"></a>
 
-    <!-- Header -->
-    <div id="header">
-        <div class="wrap" id="header-wrap">
-          <div class="col-3 logo-wear">
-          <a href="/wear/index.html">
-            <img src="/wear/images/android-wear.png" height="16" alt="Android Wear" />
-          </a>
-          </div>
+<!-- Header -->
+<div id="header-wrapper">
+  <div id="header">
+    <div class="wrap" id="header-wrap">
+      <div class="col_3 logo wear-logo">
+        <a href="/wear/index.html">
+          <img src="/wear/images/android-wear.png" height="16" alt="Android Wear" />
+        </a>
+      </div>
+      <div class="col-8" style="margin:0"><h1 style="margin:1px 0 0 20px;padding:0;line-height:16px;
+color:#666;font-weight:100;font-size:24px;">Developer Preview</h1></div>
 
-
-	<div class="col-8" style="margin:0"><h1 style="margin:1px 0 0 20px;padding:0;line-height:16px;
-  color:#666;font-weight:100;font-size:24px;">Developer Preview</h1></div>
-            
-
-          <!-- New Search -->
-          <div class="menu-container">
-            <div class="moremenu">
-	        <div id="more-btn"></div>
-	    </div>
+      
+      
+<div class="menu-container">
+  <div class="moremenu">
+    <div id="more-btn"></div>
+  </div>
   <div class="morehover" id="moremenu">
     <div class="top"></div>
     <div class="mid">
       <div class="header">Links</div>
       <ul>
-        <li><a href="https://play.google.com/apps/publish/">Google Play Developer Console</a></li>
+        <li><a href="https://play.google.com/apps/publish/" target="_googleplay">Google Play Developer Console</a></li>
         <li><a href="http://android-developers.blogspot.com/">Android Developers Blog</a></li>
         <li><a href="/about/index.html">About Android</a></li>
       </ul>
@@ -172,16 +166,32 @@
         <li class="active"><a>Android Developers</a></li>
         <li><a href="http://source.android.com">Android Open Source Project</a></li>
       </ul>
-      
-      
-      
-      
 
-
+      
+      
+        <div class="header">Language</div>
+          <div id="language" class="locales">
+            <select name="language" onChange="changeLangPref(this.value, true)">
+                <option value="en">English</option>
+                <option value="es">Español</option>
+                <option value="ja">日本語</option>
+                <option value="ko">한국어</option>
+                <option value="ru">Русский</option>
+                <option value="zh-cn">中文 (中国)</option>
+                <option value="zh-tw">中文 (台灣)</option>
+            </select>
+          </div>
+        <script type="text/javascript">
+          <!--
+          loadLangPref();
+            //-->
+        </script>
+      
+      
       <br class="clearfix" />
-    </div><!-- end mid -->
+    </div><!-- end 'mid' -->
     <div class="bottom"></div>
-  </div><!-- end morehover -->
+  </div><!-- end 'moremenu' -->
 
   <div class="search" id="search-container">
     <div class="search-inner">
@@ -189,16 +199,16 @@
       <div class="left"></div>
       <form onsubmit="return submit_search()">
         <input id="search_autocomplete" type="text" value="" autocomplete="off" name="q"
-onfocus="search_focus_changed(this, true)" onblur="search_focus_changed(this, false)"
-onkeydown="return search_changed(event, true, '/')" 
-onkeyup="return search_changed(event, false, '/')" />
+          onfocus="search_focus_changed(this, true)" onblur="search_focus_changed(this, false)"
+          onkeydown="return search_changed(event, true, '/')"
+          onkeyup="return search_changed(event, false, '/')" />
       </form>
       <div class="right"></div>
-        <a class="close hide">close</a>
-        <div class="left"></div>
-        <div class="right"></div>
-    </div>
-  </div><!--  end search -->
+      <a class="close hide">close</a>
+      <div class="left"></div>
+      <div class="right"></div>
+    </div><!-- end search-inner -->
+  </div><!-- end search-container -->
 
   <div class="search_filtered_wrapper reference">
     <div class="suggest-card reference no-display">
@@ -227,30 +237,37 @@
       <ul class="search_filtered">
       </ul>
     </div>
-  </div><!-- end search_filtered_wrapper -->
-
   </div>
-  <!-- end menu_container -->
+</div><!-- end menu-container (search and menu widget) -->
 
 
-        </div><!-- end header-wrap -->
-    </div>
-    <!-- /Header -->
+    </div><!-- end header-wrap -->
+  </div><!-- /Header -->
 
 
   <div id="searchResults" class="wrap" style="display:none;">
           <h2 id="searchTitle">Results</h2>
           <div id="leftSearchControl" class="search-control">Loading...</div>
   </div>
+</div> <!--end header-wrapper -->
+
+<div id="sticky-header">
+  <div>
+    <a class="logo" href="#top"></a>
+    <a class="top" href="#top"></a>
+    <ul class="breadcrumb">
+      
+      <li class="current">WearableNotifications.Builder</li>
+    </ul>
+  </div>
+</div>
 
   
 
-  
 
   <div class="wrap clearfix" id="body-content">
     <div class="col-4" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
       <div id="devdoc-nav" class="scroll-pane">
-<a class="totop" href="#top" data-g-event="left-nav-top">to top</a>
 
 <ul id="nav">
 
@@ -327,7 +344,7 @@
 
 </ul>
 
-        
+
 
       </div>
     </div> <!-- end side-nav -->
@@ -340,6 +357,7 @@
 
 
 
+
 <div class="col-12"  id="doc-col">
 
 <div id="api-info-block">
diff --git a/docs/html/reference/android/preview/support/wearable/notifications/WearableNotifications.html b/docs/html/reference/android/preview/support/wearable/notifications/WearableNotifications.html
index e03e16e..c9948b8 100644
--- a/docs/html/reference/android/preview/support/wearable/notifications/WearableNotifications.html
+++ b/docs/html/reference/android/preview/support/wearable/notifications/WearableNotifications.html
@@ -82,13 +82,6 @@
 
 
 
-
-
-
-
-
-
-
 <html>
 <head>
 
@@ -101,13 +94,15 @@
 
 <!-- STYLESHEETS -->
 <link rel="stylesheet"
-href="http://fonts.googleapis.com/css?family=Roboto:light,regular,medium,thin,italic,mediumitalic,bold" title="roboto">
+href="//fonts.googleapis.com/css?family=Roboto+Condensed">
+<link rel="stylesheet" href="//fonts.googleapis.com/css?family=Roboto:light,regular,medium,thin,italic,mediumitalic,bold"
+  title="roboto">
 <link href="/assets/css/default.css" rel="stylesheet" type="text/css">
 
 
 
 <!-- JAVASCRIPT -->
-<script src="http://www.google.com/jsapi" type="text/javascript"></script>
+<script src="//www.google.com/jsapi" type="text/javascript"></script>
 <script src="/assets/js/android_3p-bundle.js" type="text/javascript"></script>
 <script type="text/javascript">
   var toRoot = "/";
@@ -130,7 +125,7 @@
 </head>
 
 <body class="gc-documentation 
-  develop" itemscope itemtype="http://schema.org/Article">
+  preview" itemscope itemtype="http://schema.org/Article">
   <div id="doc-api-level" class="" style="display:none"></div>
   <a name="top"></a>
 
@@ -138,31 +133,30 @@
   
 <a name="top"></a>
 
-    <!-- Header -->
-    <div id="header">
-        <div class="wrap" id="header-wrap">
-          <div class="col-3 logo-wear">
-          <a href="/wear/index.html">
-            <img src="/wear/images/android-wear.png" height="16" alt="Android Wear" />
-          </a>
-          </div>
+<!-- Header -->
+<div id="header-wrapper">
+  <div id="header">
+    <div class="wrap" id="header-wrap">
+      <div class="col_3 logo wear-logo">
+        <a href="/wear/index.html">
+          <img src="/wear/images/android-wear.png" height="16" alt="Android Wear" />
+        </a>
+      </div>
+      <div class="col-8" style="margin:0"><h1 style="margin:1px 0 0 20px;padding:0;line-height:16px;
+color:#666;font-weight:100;font-size:24px;">Developer Preview</h1></div>
 
-
-	<div class="col-8" style="margin:0"><h1 style="margin:1px 0 0 20px;padding:0;line-height:16px;
-  color:#666;font-weight:100;font-size:24px;">Developer Preview</h1></div>
-            
-
-          <!-- New Search -->
-          <div class="menu-container">
-            <div class="moremenu">
-	        <div id="more-btn"></div>
-	    </div>
+      
+      
+<div class="menu-container">
+  <div class="moremenu">
+    <div id="more-btn"></div>
+  </div>
   <div class="morehover" id="moremenu">
     <div class="top"></div>
     <div class="mid">
       <div class="header">Links</div>
       <ul>
-        <li><a href="https://play.google.com/apps/publish/">Google Play Developer Console</a></li>
+        <li><a href="https://play.google.com/apps/publish/" target="_googleplay">Google Play Developer Console</a></li>
         <li><a href="http://android-developers.blogspot.com/">Android Developers Blog</a></li>
         <li><a href="/about/index.html">About Android</a></li>
       </ul>
@@ -172,16 +166,32 @@
         <li class="active"><a>Android Developers</a></li>
         <li><a href="http://source.android.com">Android Open Source Project</a></li>
       </ul>
-      
-      
-      
-      
 
-
+      
+      
+        <div class="header">Language</div>
+          <div id="language" class="locales">
+            <select name="language" onChange="changeLangPref(this.value, true)">
+                <option value="en">English</option>
+                <option value="es">Español</option>
+                <option value="ja">日本語</option>
+                <option value="ko">한국어</option>
+                <option value="ru">Русский</option>
+                <option value="zh-cn">中文 (中国)</option>
+                <option value="zh-tw">中文 (台灣)</option>
+            </select>
+          </div>
+        <script type="text/javascript">
+          <!--
+          loadLangPref();
+            //-->
+        </script>
+      
+      
       <br class="clearfix" />
-    </div><!-- end mid -->
+    </div><!-- end 'mid' -->
     <div class="bottom"></div>
-  </div><!-- end morehover -->
+  </div><!-- end 'moremenu' -->
 
   <div class="search" id="search-container">
     <div class="search-inner">
@@ -189,16 +199,16 @@
       <div class="left"></div>
       <form onsubmit="return submit_search()">
         <input id="search_autocomplete" type="text" value="" autocomplete="off" name="q"
-onfocus="search_focus_changed(this, true)" onblur="search_focus_changed(this, false)"
-onkeydown="return search_changed(event, true, '/')" 
-onkeyup="return search_changed(event, false, '/')" />
+          onfocus="search_focus_changed(this, true)" onblur="search_focus_changed(this, false)"
+          onkeydown="return search_changed(event, true, '/')"
+          onkeyup="return search_changed(event, false, '/')" />
       </form>
       <div class="right"></div>
-        <a class="close hide">close</a>
-        <div class="left"></div>
-        <div class="right"></div>
-    </div>
-  </div><!--  end search -->
+      <a class="close hide">close</a>
+      <div class="left"></div>
+      <div class="right"></div>
+    </div><!-- end search-inner -->
+  </div><!-- end search-container -->
 
   <div class="search_filtered_wrapper reference">
     <div class="suggest-card reference no-display">
@@ -227,30 +237,37 @@
       <ul class="search_filtered">
       </ul>
     </div>
-  </div><!-- end search_filtered_wrapper -->
-
   </div>
-  <!-- end menu_container -->
+</div><!-- end menu-container (search and menu widget) -->
 
 
-        </div><!-- end header-wrap -->
-    </div>
-    <!-- /Header -->
+    </div><!-- end header-wrap -->
+  </div><!-- /Header -->
 
 
   <div id="searchResults" class="wrap" style="display:none;">
           <h2 id="searchTitle">Results</h2>
           <div id="leftSearchControl" class="search-control">Loading...</div>
   </div>
+</div> <!--end header-wrapper -->
+
+<div id="sticky-header">
+  <div>
+    <a class="logo" href="#top"></a>
+    <a class="top" href="#top"></a>
+    <ul class="breadcrumb">
+      
+      <li class="current">WearableNotifications</li>
+    </ul>
+  </div>
+</div>
 
   
 
-  
 
   <div class="wrap clearfix" id="body-content">
     <div class="col-4" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
       <div id="devdoc-nav" class="scroll-pane">
-<a class="totop" href="#top" data-g-event="left-nav-top">to top</a>
 
 <ul id="nav">
 
@@ -327,7 +344,7 @@
 
 </ul>
 
-        
+
 
       </div>
     </div> <!-- end side-nav -->
@@ -340,6 +357,7 @@
 
 
 
+
 <div class="col-12"  id="doc-col">
 
 <div id="api-info-block">
diff --git a/docs/html/sdk/installing/index.jd b/docs/html/sdk/installing/index.jd
index 9d5e8c1..6b63ba7 100644
--- a/docs/html/sdk/installing/index.jd
+++ b/docs/html/sdk/installing/index.jd
@@ -35,10 +35,10 @@
 
 </div>
 
-  
+
 
 <div id="mac" class="docs" style="display:none">
-  
+
 <h3>Getting started on Mac</h3>
 
 <ol>
@@ -62,7 +62,7 @@
 
 
 <div id="linux" class="docs" style="display:none">
-  
+
 <h3>Getting started on Linux</h3>
 
 <ol>
@@ -97,17 +97,23 @@
   <li>Here are the steps to install Java and Eclipse, prior to installing
   the Android SDK and ADT Plugin.
     <ol>
-      <li>If you are running a 64-bit distribution on your development
-      machine, you need to install the <code>ia32-libs</code> package using
-      <code>apt-get:</code>:
-      <pre>apt-get install ia32-libs</pre>
+      <li><p>If you are running a 64-bit distribution on your development
+      machine, you need to install additional packages first. For Ubuntu 13.10 (Saucy Salamander)
+      and above, install the <code>libncurses5:i386</code>, <code>libstdc++6:i386</code>, and
+      <code>zlib1g:i386</code> packages using <code>apt-get</code>:</p>
+      <pre class="no-pretty-print">sudo dpkg --add-architecture i386
+sudo apt-get update
+sudo apt-get install libncurses5:i386 libstdc++6:i386 zlib1g:i386</pre>
+      <p>For earlier versions of Ubuntu, install the <code>ia32-libs</code> package using
+      <code>apt-get</code>:</p>
+      <pre class="no-pretty-print">apt-get install ia32-libs</pre>
       </li>
-      <li>Next, install Java: <pre>apt-get install sun-java6-jdk</pre></li>
-      <li>The Ubuntu package manager does not currently offer an Eclipse 3.6
+      <li>Next, install Java: <pre class="no-pretty-print">apt-get install sun-java6-jdk</pre></li>
+      <li>The Ubuntu package manager does not currently offer an Eclipse 3.7
       version for download, so we recommend that you download Eclipse from
       eclipse.org (<a
-      href="http://www.eclipse.org/downloads/">http://www.eclipse.org/
-      downloads/</a>). A Java or RCP version of Eclipse is recommended.</li>
+      href="http://www.eclipse.org/downloads/">http://www.eclipse.org/downloads/</a>).
+      A Java or RCP version of Eclipse is recommended.</li>
       <li>Follow the steps given in previous sections to install the SDK
       and the ADT plugin. </li>
     </ol>
@@ -137,7 +143,7 @@
     // not running a compatible OS, so just show all the docs
     $('.docs').show();
   }
-  
+
   function showAll() {
     $('.docs').each(function() {
       if (!$(this).is(':visible')) {
diff --git a/docs/html/sdk/installing/installing-adt.jd b/docs/html/sdk/installing/installing-adt.jd
index 1f5ca11..7bf366c 100644
--- a/docs/html/sdk/installing/installing-adt.jd
+++ b/docs/html/sdk/installing/installing-adt.jd
@@ -1,8 +1,8 @@
 page.title=Installing the Eclipse Plugin
-adt.zip.version=22.6.2
-adt.zip.download=ADT-22.6.2.zip
-adt.zip.bytes=14586842
-adt.zip.checksum=f660959fa71262b4285bcb64be284bf5
+adt.zip.version=22.6.3
+adt.zip.download=ADT-22.6.3.zip
+adt.zip.bytes=14590813
+adt.zip.checksum=3982259fd2cc81e53bbbe05dcd6529a7
 
 @jd:body
 
@@ -35,10 +35,10 @@
     <li>In the Add Repository dialog that appears, enter "ADT Plugin" for the <em>Name</em> and the
 following URL for the <em>Location</em>:
       <pre>https://dl-ssl.google.com/android/eclipse/</pre>
+      <p class="note"><strong>Note:</strong> The Android Developer Tools update site requires
+      a secure connection. Make sure the update site URL you enter starts with HTTPS.</p>
     </li>
-    <li>Click <strong>OK</strong>.
-      <p>If you have trouble acquiring the plugin, try using "http" in the Location URL,
-instead of "https" (https is preferred for security reasons).</p></li>
+    <li>Click <strong>OK</strong>.</li>
     <li>In the Available Software dialog, select the checkbox next to Developer Tools and click
 <strong>Next</strong>.</li>
     <li>In the next window, you'll see a list of the tools to be downloaded. Click
@@ -75,7 +75,7 @@
 <div class="sidebox-wrapper">
 <div class="sidebox">
 <h2>App Translations in Google Play</h2>
-<p>Google Play <a href="{@docRoot}distribute/googleplay/publish/localizing.html#gp-trans">App
+<p>Google Play <a href="{@docRoot}distribute/tools/localization-checklist.html#gp-trans">App 
 Translation Service</a> is available in the Developer Console to help you
 localize your app for a global user base. You can browse qualified vendors, get
 estimates, upload strings for translation, and then import the translations directly
@@ -99,7 +99,7 @@
 localization works instantly.</p>
 
 <p>For more information about translation services in Google Play, see <a
-href="{@docRoot}distribute/googleplay/publish/localizing.html#gp-trans">Purchase
+href="{@docRoot}distribute/tools/localization-checklist.html#gp-trans">Purchase
 professional translations through the Developer Console</a>.</p>
 
 <p>To install the ADT Translation Manager Plugin follow these steps:</p>
@@ -129,7 +129,7 @@
 <ul>
 <li>The full ADT Plugin must be installed in your Eclipse environment before you install the ADT Translation Manager Plugin.</li>
 <li>ADT Translation Manager Plugin is designed for use with the translation services offered through the Google Play Developer Console. It is not designed for general purpose import/export of strings. </li>
-<li>To use the plugin, you must <a href="{@docRoot}distribute/googleplay/publish/register.html">set up a Developer Console account</a>. </li>
+<li>To use the plugin, you must <a href="{@docRoot}distribute/googleplay/start.html">set up a Developer Console account</a>. </li>
 <li>Currently, translation services are available through the Developer Console only as part of a pilot program. To use the plugin, you must first sign up for the pilot program by visiting the Developer Console.</li>
 <li>If you downloaded ADT as part of the SDK ADT bundle, you may encounter an error when attempting to download the ADT Translation Manager Plugin from the remote repository. In that case, open the <strong>Install New
 Software</strong>, uncheck "Contact all update sites during install to find required software" at the bottom and try again. </li>
@@ -139,23 +139,16 @@
 
 <h2 id="Troubleshooting">Troubleshooting ADT Installation</h2>
 
-<p> If you are having trouble downloading the ADT plugin after following the
-steps above, here are some suggestions: </p>
-
-<ul>
-  <li>If Eclipse can not find the remote update site containing the ADT plugin,
-try changing the remote site URL to use http, rather than https. That is, set
-the Location for the remote site to:
-<pre>http://dl-ssl.google.com/android/eclipse/</pre></li>
-<li>If you are behind a firewall (such as a corporate firewall), make sure that
+<p>If you are having trouble downloading the ADT plugin after following the
+steps above and you are behind a firewall (such as a corporate firewall), make sure that
 you have properly configured your proxy settings in Eclipse. In Eclipse,
 you can configure proxy information from the main Eclipse menu in
 <strong>Window</strong> (on Mac OS X, <strong>Eclipse</strong>) &gt;
 <strong>Preferences</strong> &gt; <strong>General</strong> &gt; <strong>Network
-Connections</strong>.</li>
-</ul>
+Connections</strong>.
+</p>
 
-<p> If you are still unable to use Eclipse to download the ADT plugin as a
+<p>If you are still unable to use Eclipse to download the ADT plugin as a
 remote update site, you can download the ADT zip file to your local machine and
 manually install it:</p>
 
diff --git a/docs/html/sdk/installing/studio-build.jd b/docs/html/sdk/installing/studio-build.jd
new file mode 100644
index 0000000..2a616a0
--- /dev/null
+++ b/docs/html/sdk/installing/studio-build.jd
@@ -0,0 +1,1070 @@
+page.title=Building Your Project with Gradle
+
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+<h2>In this document</h2>
+<ol>
+    <li><a href="#overviewBuild">Overview of the Build System</a>
+        <ol>
+            <li><a href="#buildConf">Build configuration</a></li>
+            <li><a href="#buildConv">Build by convention</a></li>
+            <li><a href="#projectModules">Projects and modules</a></li>
+            <li><a href="#dependencies">Dependencies</a></li>
+            <li><a href="#buildTasks">Build tasks</a></li>
+            <li><a href="#gradleWrapper">The Gradle wrapper</a></li>
+        </ol>
+    </li>
+    <li><a href="#creatingBuilding">Create and Build a Project</a>
+        <ol>
+            <li><a href="#createProject">Create a project</a></li>
+            <li><a href="#projectStructure">Project structure</a></li>
+            <li><a href="#addLibModule">Add a library module</a></li>
+            <li><a href="#buildProject">Build the project</a></li>
+            <li><a href="#buildCmd">Build from the command line</a></li>
+            <li><a href="#buildRelease">Build a release version</a></li>
+        </ol>
+    </li>
+    <li><a href="#configBuild">Configure the Build</a>
+        <ol>
+            <li><a href="#buildFileBasics">Build file basics</a></li>
+            <li><a href="#declareDeps">Declare dependencies</a></li>
+            <li><a href="#runProguard">Run ProGuard</a></li>
+            <li><a href="#configureSigning">Configure signing settings</a></li>
+            <li><a href="#workBuildVariants">Work with build variants</a></li>
+        </ol>
+    </li>
+    <li><a href="#reference">Reference</a></li>
+</ol>
+<h2>See also</h2>
+<ul>
+<li><a href="{@docRoot}sdk/installing/studio.html">
+Getting Started with Android Studio</a></li>
+<li><a href="{@docRoot}sdk/installing/studio-tips.html">
+Android Studio Tips and Tricks</a></li>
+<li><a href="{@docRoot}sdk/installing/migrate.html">
+Migrating from Eclipse</a></li>
+</div>
+</div>
+
+<a class="notice-developers-video"
+href="https://developers.google.com/events/io/sessions/324603352">
+<div>
+    <h3>Video</h3>
+    <p>What's New in Android Developer Tools</p>
+</div>
+</a>
+
+<p>The Android Studio build system is the toolkit you use to build, test, run and package
+your apps. The build system is independent from Android Studio, so you can invoke it from Android
+Studio or from the command line. After you write your application, you can use the features
+of the build system to:</p>
+
+<ul>
+    <li>Customize, configure, and extend the build process.</li>
+    <li>Create multiple APKs for your app with different features using the same project.</li>
+    <li>Reuse code and resources.</li>
+</ul>
+
+<p>The flexibility of the Android Studio build system enables you to achieve all of this without
+modifying your app's core project files.</p>
+
+
+<h2 id="overviewBuild">Overview of the Build System</h2>
+
+<p>The Android Studio build system consists of an Android plugin for <em>Gradle</em>.
+<a href="http://www.gradle.org/">Gradle</a> is an advanced build toolkit that manages dependencies
+and allows you to define custom build logic. Many software projects use Gradle to manage their
+builds. The Android plugin for Gradle does not depend on Android Studio, although Android Studio
+is fully integrated with it. This means that:</p>
+
+<ul>
+    <li>You can build your Android apps from the command line on your machine or on machines
+        where Android Studio is not installed (such as continuous integration servers).</li>
+    <li>You can build your Android apps from Android Studio with the same custom build
+        configuration and logic as when you build from the command line.</li>
+</ul>
+
+<p>The output of the build is the same whether you are building a project from the command line,
+on a remote machine, or using Android Studio.</p>
+
+<h3 id="buildConf">Build configuration</h3>
+
+<p>The build configuration for your project is defined inside <em>Gradle build files</em>,
+which are plain text files that use the syntax and options from Gradle and the Android plugin
+to configure the following aspects of your build:</p>
+
+<ul>
+    <li><em>Build variants</em>. The build system can generate multiple APKs with different
+        configurations for the same project. This is useful when you want to build different
+        versions of your application without having to create a separate project for each of
+        them.</li>
+    <li><em>Dependencies</em>. The build system manages project dependencies and supports
+        dependencies from your local filesystem and from remote repositories. This prevents you
+        from having to search, download, and copy binary packages for your dependencies into your
+        project directory.</li>
+    <li><em>Manifest entries</em>. The build system enables you to specify values for some
+        elements of the manifest file in the build configuration. These new values override the
+        existing values in the manifest file. This is useful if you want to generate multiple APKs
+        for your project where each of them has a different package name, minimum SDK version, or
+        target SDK version.</li>
+    <li><em>Signing</em>. The build system enables you to specify signing settings in the build
+        configuration, and it can sign your APKs during the build process.</li>
+    <li><em>ProGuard</em>. The build system enables you to specify a different
+        <a href="{@docRoot}tools/help/proguard.html">ProGuard</a> rules
+        file for each build variant. The build system can run ProGuard to obfuscate your classes
+        during the build process.</li>
+    <li><em>Testing</em>. The build system generates a test APK from the test sources in your
+        project, so you do not have to create a separate test project. The build system can run
+        your tests during the build process.</li>
+</ul>
+
+<p>Gradle build files use <em>Groovy</em> syntax.
+<a href="http://groovy.codehaus.org/">Groovy</a> is a dynamic language that you can use to
+define custom build logic and to interact with the Android-specific elements provided by the
+Android plugin for Gradle.</p>
+
+<h3 id="buildConv">Build by convention</h3>
+
+<p>The Android Studio build system assumes <em>sensible defaults</em> for the project structure
+and other build options. If your project adheres to these conventions, your Gradle build files are
+very simple. When some these conventions do not apply to your project, the flexibility of the
+build system allows you to configure almost every aspect of the build process. For example, if
+the sources for your project are located in a different directory than the default, you can
+specify this location in the build file.</p>
+
+<h3 id="projectModules">Projects and modules</h3>
+
+<p>A <em>project</em> in Android Studio represents a complete Android app. Android Studio
+projects consist of one or more modules. A <em>module</em> is a component of your app that you can
+build, test, or debug independently. Modules contain the source code and resources for your app.
+Android Studio projects contain three kinds of modules:</p>
+
+<ul>
+    <li><em>Java library modules</em> contain reusable code. The build system generates a
+        JAR package for Java library modules.</li>
+    <li><em>Android library modules</em> contain reusable Android-specific code and resources.
+        The build system generates an AAR (Android ARchive) package for library modules.</li>
+    <li><em>Android application modules</em> contain application code and may depend on library
+        modules, although many Android apps consists of only one application module. The build
+        system generates an APK package for application modules.</li>
+</ul>
+
+<p>Android Studio projects contain a top-level Gradle build file that lists all the modules in
+the project, and each module contains its own Gradle build file.</p>
+
+<h3 id="dependencies">Dependencies</h3>
+
+<p>The Android Studio build system manages project dependencies and supports module dependencies,
+local binary dependencies, and remote binary dependencies.</p>
+
+<dl>
+    <dt><em>Module Dependencies</em></dt>
+    <dd><p>A project module can include in its build file a list of other modules it depends on.
+        When you build this module, the build system assembles and includes the required
+        modules.</p></dd>
+    <dt><em>Local Dependencies</em></dt>
+    <dd><p>If you have binary archives in your local filesystem that a module depends on, such as
+        JAR files, you can declare these dependencies in the build file for that
+        module.</p></dd>
+    <dt><em>Remote Dependencies</em></dt>
+    <dd><p>When some of your dependencies are available in a remote repository, you do not have
+        to download them and copy them into your project. The Android Studio build system supports
+        remote <em>Maven</em> dependencies. <a href="http://maven.apache.org/">Maven</a> is a
+        popular software project management tool that helps organize project dependencies using
+        repositories.</p>
+        <p>Many popular software libraries and tools are available in public Maven repositories.
+        For these dependencies you only have to specify their Maven coordinates, which uniquely
+        identify each element in a remote repository. The format for Maven coordinates used in the
+        build system is <code>group:name:version</code>. For example, the Maven coordinates for
+        version 16.0.1 of the Google Guava libraries are
+        <code>com.google.guava:guava:16.0.1</code>.</p>
+        <p>The <a href="http://search.maven.org">Maven Central Repository</a> is widely used to
+        distribute many libraries and tools.</p>
+    </dd>
+</dl>
+
+<h3 id="buildTasks">Build tasks</h3>
+
+<p>The Android Studio build system defines a hierarchical set of build tasks: the top-level
+tasks invoke the tasks they depend on to produce the necessary outcomes. The build system
+provides project tasks to build your app and module tasks to build modules independently.</p>
+
+<p>You can view the list of available tasks and invoke any task from Android Studio and from
+the command line, as described in
+<a href="#buildProject">Build the project in Android Studio</a> and and
+<a href="#buildCmd">Build the project from the command line</a>.</p>
+
+<h3 id="gradleWrapper">The Gradle wrapper</h3>
+
+<p>Android Studio projects contain the <em>Gradle wrapper</em>, which consists of:</p>
+
+<ul>
+    <li>A JAR file</li>
+    <li>A properties file</li>
+    <li>A shell script for Windows platforms</li>
+    <li>A shell script for Mac and Linux platforms</li>
+</ul>
+
+<p class="note"><strong>Note:</strong> You should submit all of these files to your source
+control system.</p>
+
+<p>Using the Gradle wrapper (instead of the local Gradle installation) ensures that
+you always run the version of Gradle defined in the properties file. To configure your project
+to use a newer version of Gradle, edit the properties file and specify the new version there.
+
+<p>Android Studio reads the properties file from the Gradle wrapper directory inside your project
+and runs the wrapper from this directory, so you can seamlessly work with multiple projects
+that require different versions of Gradle.</p>
+
+<p class="note"><strong>Note:</strong> Android Studio does not use the shell scripts, so any
+changes you make to them won't work when building from the IDE. You should define your custom
+logic inside Gradle build files instead.</p>
+
+<p>You can run the shell scripts to build your project from the command line on your development
+machine and on other machines where Android Studio is not installed.</p>
+
+
+<h2 id="creatingBuilding">Create and Build an Android Studio Project</h2>
+
+<p>This section builds on the concepts presented above and shows you how to:</p>
+
+<ul>
+    <li>Create projects and modules.</li>
+    <li>Work with the project structure.</li>
+    <li>Edit build files to configure the build process.</li>
+    <li>Build and run your app.</li>
+</ul>
+
+<h3 id="createProject">Create a project in Android Studio</h3>
+
+<p>To create a new project in Android Studio:</p>
+
+<ol>
+    <li>Click <strong>File</strong> and select <strong>New Project</strong>.</li>
+    <li>In the window that appears, enter "BuildSystemExample" in the <em>Application</em>
+        name field.</li>
+    <li>Leave the rest of the values unchanged and click <strong>Next</strong>.</li>
+    <li>Leave the default icon settings unchanged and click <strong>Next</strong>.</li>
+    <li>Select <em>Blank Activity</em> and click <strong>Next</strong>.</li>
+    <li>Leave the default activity and layout names unchanged and click
+        <strong>Finish</strong>.</li>
+</ol>
+
+<p>Figure 1 shows how the Android Studio window looks like after creating the project.</p>
+
+<img src="{@docRoot}images/tools/as-mainscreen.png" alt="" />
+<p class="img-caption"><strong>Figure 1.</strong> Previewing your app.</p>
+
+<h3 id="projectStructure">The project structure</h3>
+
+<p>Android Studio projects contain an application module by default (<code>app</code>).
+Table 1 lists where the main components of your app are located inside this module.</p>
+
+<p class="table-caption" id="table1">
+<strong>Table 1.</strong> Default location of the components in an application module.</p>
+<table>
+    <tr>
+        <th scope="col">Component</th>
+        <th scope="col">Location</th>
+    </tr>
+    <tr>
+        <td>Source files</td>
+        <td><code>app/src/main/java/&lt;package>/</code></td>
+    </tr>
+    <tr>
+        <td>Resource files</td>
+        <td><code>app/src/main/res/</code></td>
+    </tr>
+    <tr>
+        <td>Manifest file</td>
+        <td><code>app/src/main/AndroidManifest.xml</code></td>
+    </tr>
+    <tr>
+        <td>Build file</td>
+        <td><code>app/build.gradle</code></td>
+    </tr>
+</table>
+
+<p>When you add additional modules to your project, the directory structure for each module is
+similar to the one shown in table 1, replacing <code>app</code> by the name of the module.</p>
+
+<h3 id="addLibModule">Add a library module</h3>
+
+<p>This section shows you how to add a library module to your project and how to add this
+library as a dependency of an application module.</p>
+
+<h4>Create a new library module</h4>
+
+<p>It is good development practice to group functionality that you may reuse in other apps inside
+a library module. To create a library module inside the <code>BuildSystemExample</code>
+project:</p>
+
+<ol>
+    <li>Click <strong>File</strong> and select <strong>New Module</strong>.</li>
+    <li>On the window that appears, select <strong>Android Library</strong> and click
+        <strong>Next</strong>.</li>
+    <li>Leave the default module name (<code>lib</code>) unchanged and click
+        <strong>Next</strong>.</li>
+    <li>Select <em>Blank Activity</em> and click <strong>Next</strong>.</li>
+    <li>Type "LibActivity1" on the <em>Activity Name</em> field and click
+        <strong>Finish</strong>.</li>
+</ol>
+
+<p>The project now contains two modules, <code>app</code> and <code>lib</code>, with one activity
+in each module.</p>
+
+<h4 id="openActFromLib">Open an activity from a library module</h4>
+
+<p>Library modules contain activities and other logic that one or more application modules reuse.
+In this example, <code>MainActivity</code> in the app module opens <code>LibActivity1</code>
+from the <code>lib</code> module. To open <code>LibActivity1</code> from
+<code>MainActivity</code>:</p>
+
+<ol>
+    <li>
+        <p>Edit the layout file for <code>MainActivity</code> in the <code>app</code> module.
+        This file is located in <code>app/src/main/res/layout/activity_main.xml</code>. Replace
+        the contents of this file with the following:</p>
+        <p><pre>
+&lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    tools:context="com.buildsystemexample.app.MainActivity">
+
+    &lt;Button
+        android:id="@+id/button1"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/button1"
+        android:onClick="onButton1Clicked"/>
+
+&lt;/LinearLayout>
+</pre></p>
+    </li>
+    <li>
+        In this layout file, click on the line that contains
+        <code>android:text="@string/button1"</code> and press <strong>Alt+Enter</strong>. Follow
+        the suggestion from Android Studio to add a string resource with the value
+        "Open LibActivity1".
+    </li>
+    <li>
+        In this layout file, click on the line that contains
+        <code>android:onClick="onButton1Clicked"</code> and press <strong>Alt+Enter</strong>.
+        Follow the suggestion from Android Studio to add the <code>onButton1Clicked</code>
+        method to <code>MainActivity</code>.
+    </li>
+    <li>
+        <p>Copy the following code inside the <code>onButton1Clicked</code> method in
+        <code>MainActivity</code>:</p>
+        <p><pre>
+public void onButton1Clicked(View view) {
+    Intent intent = new Intent(this, LibActivity1.class);
+    startActivity(intent);
+}</pre></p>
+    </li>
+    <li>
+        Click on <code>LibActivity1</code> in the first line inside the
+        <code>onButton1Clicked</code> method of <code>MainActivity</code> and press
+        <strong>Alt+Enter</strong>. Follow the suggestion from Android Studio to add an import
+        for <code>LibActivity1</code> from the lib module.
+    </li>
+</ol>
+
+<p>When the user taps the <strong>Open LibActivity1</strong> button on <code>MainActivity</code>
+(from the <code>app</code> module), <code>LibActivity1</code> (from the <code>lib</code> module)
+starts.</p>
+
+<h4>Add a dependency on a library module</h4>
+
+<p>The <code>app</code> module now depends on the <code>lib</code> module, but the build system
+does not know about this yet. Edit the build file for the <code>app</code> module (
+<code>app/build.gradle</code>) and add a dependency on the <code>lib</code> module:</p>
+
+<pre>
+...
+dependencies {
+    ...
+    compile project(":lib")
+}
+</pre>
+
+<p>The <code>lib</code> module can still be built and tested independently, and the build system
+creates an AAR package for it that you could reuse in other projects.</p>
+
+<h3 id="buildProject">Build the project in Android Studio</h3>
+
+<p>To build the project on Android Studio, click <strong>Build</strong> and select
+<strong>Make Project</strong>. The status bar at the bottom of the window shows the current
+progress of the build:</p>
+
+<p><code>Gradle: Executing tasks: [:app:assembleDebug, :lib:bundleDebug]</code></p>
+
+<p class="note">If your project uses product flavors, Android Studio invokes the task for the
+selected build variant. For more information, see <a href="#workBuildVariants">Work with build
+variants.</a></p>
+
+<p>Click <img src="{@docRoot}images/tools/as-gradlebutton.png" alt=""
+style="vertical-align:bottom;margin:0;"/> on the bottom
+right part of the window to show the <em>Gradle Console</em>, as shown in figure 2.</p>
+
+<img src="{@docRoot}images/tools/as-gradleconsole.png" alt="" />
+<p class="img-caption"><strong>Figure 2.</strong> The Gradle Console in Android Studio.</p>
+
+<p>The Gradle Console shows the build tasks and subtasks that the build system runs for
+Android Studio. If the build fails, you can find more details on the console. To hide the Gradle
+Console, click <img src="{@docRoot}images/tools/as-gradlebutton.png" alt=""
+style="vertical-align:bottom;margin:0;"/> again.</p>
+
+<p>To view the list of all available build tasks in Android Studio, click <strong>Gradle</strong>
+on the right side of the IDE window. The <em>Gradle tasks</em> panel appears as shown in
+figure 3. Double-click any build task to run it in Android Studio. To hide the <em>Gradle tasks</em>
+panel, click <strong>Gradle</strong> again.</p>
+
+<img src="{@docRoot}images/tools/as-gradlepanel.png" alt="" />
+<p class="img-caption"><strong>Figure 3.</strong> The list of build tasks in Android Studio.</p>
+
+
+<h3 id="buildCmd">Build the project from the command line</h3>
+
+<p>To build the project from the command line, open a terminal window and navigate to the project
+root. On Windows platforms, type this command:</p>
+
+<pre>
+> gradlew.bat assembleDebug
+</pre>
+
+<p>On Mac OS and Linux platforms, type these commands:</p>
+
+<pre>
+$ chmod +x gradlew
+$ ./gradlew assembleDebug
+</pre>
+
+<p>The first command (<code>chmod</code>) adds the execution permission to the Gradle wrapper
+script and is only necessary the first time you build this project from the command line.</p>
+
+<p>The output of <code>gradlew</code> is similar to the output in the Gradle Console from
+figure 2.</p>
+
+<p>The <code>assembleDebug</code> build task builds the debug version of your app and signs it
+with the default local certificate, so that you can install it on the emulator and on real devices
+for debugging purposes.</p>
+
+<p>After you build the project, the output APK for the app module is located in
+<code>app/build/apk/</code>, and the output AAR for the lib module is located in
+<code>lib/build/libs/</code>.</p>
+
+<p>To see a list of all available build tasks for your project, type this command:</p>
+
+<pre>
+$ ./gradlew tasks
+</pre>
+
+
+<h3 id="buildRelease">Build a release version</h3>
+
+<p>You can build the release version of your application from the command line or using Android
+Studio. To build it from the command line, invoke the <code>assembleRelease</code> build task using
+the Gradle wrapper script (<code>gradlew assembleRelease</code>). To build it from Android
+Studio:</p>
+
+<ol>
+    <li>Click <strong>Gradle</strong> on the right side of the IDE window.</li>
+    <li>On the <em>All tasks</em> section of the sidebar that appears, expand
+        <strong>BuildSystemExample</strong>.</li>
+    <li>Expand <strong>:app</strong> and double-click <strong>assembleRelease</strong>.</li>
+</ol>
+
+<p>You can use this procedure to invoke any build task from Android Studio.</p>
+
+
+
+<h2 id="configBuild">Configure the Build</h2>
+
+<p>This section uses the <code>BuildSystemExample</code> project from the previous section and
+shows you how to:</p>
+
+<ul>
+    <li>Use the syntax from the Android plugin for Gradle in build files.</li>
+    <li>Declare dependencies.</li>
+    <li>Configure ProGuard settings.</li>
+    <li>Configure signing settings.</li>
+    <li>Work with build variants.</li>
+</ul>
+
+<h3 id="buildFileBasics">Build file basics</h3>
+
+<p>Android Studio projects contain a top-level build file and a build file for each module. The
+build files are called <code>build.gradle</code>, and they are plain text files that use
+<a href="http://groovy.codehaus.org">Groovy</a> syntax to configure the build with the elements
+provided by the Android plugin for Gradle. In most cases, you only need to edit the build files
+at the module level. For example, the build file for the app module in the
+<code>BuildSystemExample</code> project looks like this:</p>
+
+<pre>
+apply plugin: 'android'
+
+android {
+    compileSdkVersion 19
+    buildToolsVersion "19.0.0"
+
+    defaultConfig {
+        minSdkVersion 8
+        targetSdkVersion 19
+        versionCode 1
+        versionName "1.0"
+    }
+    buildTypes {
+        release {
+            runProguard true
+            proguardFiles getDefaultProguardFile('proguard-android.txt'), \
+            'proguard-rules.txt'
+        }
+    }
+}
+
+dependencies {
+    compile project(":lib")
+    compile 'com.android.support:appcompat-v7:19.0.1'
+    compile fileTree(dir: 'libs', include: ['*.jar'])
+}
+</pre>
+
+<p><code>apply plugin: 'android'</code> applies the Android plugin for Gradle to this build.
+This adds Android-specific build tasks to the top-level build tasks and makes the
+<code>android {...}</code> element available to specify Android-specific build options.</p>
+
+<p><code>android {...}</code> configures all the Android-specific build options:</p>
+
+<ul>
+    <li>The <code>compileSdkVersion</code> property specifies the compilation target.</li>
+    <li><p>The <code>buildToolsVersion</code> property specifies what version of the build tools
+        to use. To install several versions of the build tools, use the SDK Manager.</p>
+        <p class="note"><strong>Note:</strong> Always use a build tools version whose major
+        revision number is higher or equal to that of your compilation target and target SDK.</p>
+    </li>
+    <li><p>The <code>defaultConfig</code> element configures core settings and
+        entries in the manifest file (<code>AndroidManifest.xml</code>) dynamically from the
+        build system. The values in <code>defaultConfig</code> override those in the manifest
+        file.</p>
+        <p>The configuration specified in the <code>defaultConfig</code> element applies
+        to all build variants, unless the configuration for a build variant overrides some
+        of these values.</p>
+    </li>
+    <li>The <code>buildTypes</code> element controls how to build and package your app.
+        By default, the build system defines two build types: <em>debug</em> and
+        <em>release</em>. The debug build type includes debugging symbols and is signed with
+        the debug key. The release build type is not signed by default.
+        In this example the build file configures the release version to use
+        ProGuard.</li>
+</ul>
+
+<p>The <code>dependencies</code> element is outside and after the <code>android</code> element.
+This element declares the dependencies for this module. Dependencies are covered in the following
+sections.</p>
+
+<p class="note"><strong>Note:</strong> When you make changes to the build files in your project,
+Android Studio requires a project sync to import the build configuration changes. Click
+<strong>Sync Now</strong> on the yellow notification bar that appears for Android Studio
+to import the changes.</p>
+
+<img src="{@docRoot}images/tools/as-gradlesync.png" alt="" />
+<p class="img-caption"><strong>Figure 4.</strong> Sync the project in Android Studio.</p>
+
+<h3 id="declareDeps">Declare dependencies</h3>
+
+<p>The <code>app</code> module in <code>BuildSystemExample</code> declares three
+dependencies:</p>
+
+<pre>
+...
+dependencies {
+    // Module dependency
+    compile project(":lib")
+
+    // Remote binary dependency
+    compile 'com.android.support:appcompat-v7:19.0.1'
+
+    // Local binary dependency
+    compile fileTree(dir: 'libs', include: ['*.jar'])
+}
+</pre>
+
+<p>Each of these dependencies is described below. The build system adds all the
+<code>compile</code> dependencies to the compilation classpath and includes them in the final
+package.</p>
+
+<h4>Module dependencies</h4>
+
+<p>The <code>app</code> module depends on the <code>lib</code> module, because
+<code>MainActivity</code> launches <code>LibActivity1</code> as described in
+<a href="#openActFromLib">Open an Activity from a Library Module</a>.</p>
+
+<p><code>compile project(":lib")</code> declares a dependency on the <code>lib</code>
+module of <code>BuildSystemExample</code>. When you build the <code>app</code> module,
+the build system assembles and includes the <code>lib</code> module.</p>
+
+<h4>Remote binary dependencies</h4>
+
+<p>The <code>app</code> and <code>lib</code> modules both use the <code>ActionBarActivity</code>
+class from the Android Support Library, so these modules depend on it.</p>
+
+<p><code>compile 'com.android.support:appcompat-v7:19.0.1'</code> declares a dependency on
+version 19.0.1 of the Android Support Library by specifying its Maven coordinates. The Android Support
+Library is available in the <em>Android Repository</em> package of the Android SDK. If your
+SDK installation does not have this package, download and install it using the SDK Manager.</p>
+
+Android Studio configures
+projects to use the Maven Central Repository by default. (This configuration is included in the
+top-level build file for the project.)</p>
+
+<h4>Local binary dependencies</h4>
+
+<p>The modules in <code>BuildSystemExample</code> do not use any binary dependencies from the
+local file system. If you have modules that require local binary dependencies, copy the JAR
+files for these dependencies into <code>&lt;moduleName>/libs</code> inside your project.</p>
+
+<p><code>compile fileTree(dir: 'libs', include: ['*.jar'])</code> tells the build system that any
+JAR file inside <code>app/libs</code> is a dependency and should be included in the compilation
+classpath and in the final package.</p>
+
+<p>For more information about dependencies in Gradle, see
+<a href="http://www.gradle.org/docs/current/userguide/artifact_dependencies_tutorial.html">Dependency
+Management Basics</a> in the Gradle User Guide.</p>
+
+<h3 id="runProguard">Run ProGuard</h3>
+
+<p>The build system can run
+<a href="http://developer.android.com/tools/help/proguard.html">ProGuard</a> to obfuscate your
+classes during the build process. In <code>BuildSystemExample</code>, modify the build file for
+the app module to run ProGuard for the release build:</p>
+
+<pre>
+...
+android {
+    ...
+    buildTypes {
+        release {
+            runProguard true
+            proguardFiles getDefaultProguardFile('proguard-android.txt'), \
+                          'proguard-rules.txt'
+        }
+    }
+}
+...
+</pre>
+
+<p><code>getDefaultProguardFile('proguard-android.txt')</code> obtains the default ProGuard
+settings from the Android SDK installation. Android Studio adds the module-specific rules file
+<code>proguard-rules.txt</code> at the root of the module, where you can add custom ProGuard
+rules.</p>
+
+<h3 id="configureSigning">Configure signing settings</h3>
+
+<p>The debug and the release versions of the app differ on whether the application can be
+debugged on secure devices and on how the APK is signed. The build system signs the debug
+version with a default key and certificate using known credentials to avoid a password prompt at
+build time. The build system does not sign the release version unless you explicitly define a
+signing configuration for this build.</p>
+
+<p>To sign the release version of <code>BuildSystemExample</code>:</p>
+
+<ol>
+    <li><p>Copy your release key to the root directory of the <code>app</code> module
+        (<code>app/</code>).</p>
+        <p>This ensures that the build system can find your key when you move the location of your
+        project or when you build the project on a different machine. If you do not have a release
+        key, you can generate one as described in
+        <a href="{@docRoot}tools/publishing/app-signing.html">Signing your Applications</a>.</p>
+    </li>
+    <li><p>Add the signing configuration to the build file for the <code>app</code> module:</p>
+        <p><pre>
+...
+android {
+    ...
+    defaultConfig { ... }
+    signingConfigs {
+        release {
+            storeFile file("myreleasekey.keystore")
+            storePassword "password"
+            keyAlias "MyReleaseKey"
+            keyPassword "password"
+        }
+    }
+    buildTypes {
+        release {
+            ...
+            signingConfig signingConfigs.release
+        }
+    }
+}
+...
+</pre></p>
+    </li>
+    <li>Invoke the <code>assembleRelease</code> build task from Android Studio or from the command
+        line.</li>
+</ol>
+
+<p>The package in <code>app/build/apk/app-release.apk</code> is now signed with your release key.</p>
+
+<p class="note"><strong>Note:</strong> Including the passwords for your release key and keystore
+inside the build file is not a good security practice. Alternatively, you can configure the build
+file to obtain these passwords from environment variables or have the build process prompt you
+for these passwords.</p>
+
+<p>To obtain these passwords from environment variables:</p>
+
+<pre>
+storePassword System.getenv("KSTOREPWD")
+keyPassword System.getenv("KEYPWD")
+</pre>
+
+<p>To have the build process prompt you for these passwords if you are invoking the build from
+the command line:</p>
+
+<pre>
+storePassword System.console().readLine("\nKeystore password: ")
+keyPassword System.console().readLIne("\nKey password: ")
+</pre>
+
+<h3 id="workBuildVariants">Work with build variants</h3>
+
+<p>This section describes how the build system can help you create different versions of the same
+application from a single project. This is useful when you have a demo version and a paid version
+of your app, or if you want to distribute multiple APKs for different device configurations on
+Google Play.</p>
+
+<p>The build system uses <em>product flavors</em> to create different versions of your app. Each
+version of your app can have different features or device requirements. The build system generates
+a different APK for each version of your app.</p>
+
+<h4>Build variants</h4>
+
+<p>Each version of your app is represented in the build system by a <em>build variant</em>.
+Build variants are combinations of build types and product flavor configurations. Android Studio
+projects define two build types (<em>debug</em> and <em>release</em>) and no product flavors by
+default. These projects consists of two build variants, debug and release, and the build system
+generates an APK for each.</p>
+
+<p>The exercise in this section defines two product flavors, <em>demo</em> and <em>full</em>.
+This generates four build variants:</p>
+
+<ul>
+    <li>demo-debug</li>
+    <li>demo-release</li>
+    <li>full-debug</li>
+    <li>full-release</li>
+</ul>
+
+<p>In this case the build system creates four APKs, one for each of these build variants.</p>
+
+<p>Some projects have complex combinations of features along more than one dimension, but they
+still represent the same app. For example, in addition to having a demo and a full version of the
+app, some games may contain binaries specific to a particular CPU/ABI. The flexibility of
+the build system makes it possible to generate the following build variants for such a project:</p>
+
+<ul>
+    <li>x86-demo-debug</li>
+    <li>x86-demo-release</li>
+    <li>x86-full-debug</li>
+    <li>x86-full-release</li>
+    <li>arm-demo-debug</li>
+    <li>arm-demo-release</li>
+    <li>arm-full-debug</li>
+    <li>arm-full-release</li>
+    <li>mips-demo-debug</li>
+    <li>mips-demo-release</li>
+    <li>mips-full-debug</li>
+    <li>mips-full-release</li>
+</ul>
+
+<p>This project would consist of two build types (<em>debug</em> and <em>release</em>)
+and two <em>dimensions</em> of product flavors, one for app type (demo or full) and one for
+CPU/ABI (x86, ARM, or MIPS). For more information on flavor dimensions, see the
+<a href="http://tools.android.com/tech-docs/new-build-system/user-guide">Gradle Plugin User
+Guide</a>.</p>
+
+<h4>Source directories</h4>
+
+<p>To build each version of your app, the build system combines source code and
+resources from:</p>
+
+<ul>
+    <li><code>src/main/</code> - the main source directory (common to all variants)</li>
+    <li><code>src/&lt;buildType>/</code> - the build type source directory</li>
+    <li><code>src/&lt;flavorName>/</code> - the flavor source directory</li>
+</ul>
+
+<p>The number of flavor source directories used in the build depends on the flavor configuration
+of your project:</p>
+<ul>
+    <li><p>For projects that do not define any flavors, the build system does not use any
+        flavor source directories. For example, to generate the <em>release</em> build variant
+        in projects with no flavors, the build system uses:</p>
+        <ul>
+            <li><code>src/main/</code></li>
+            <li><code>src/release/</code> (build type)</li>
+        </ul>
+    </li>
+    <li><p>For projects that define a set of flavors, the build system uses one flavor source
+        directory. For example, to generate the <em>full-debug</em> build variant in the example
+        in this section, the build system uses:</p>
+        <ul>
+            <li><code>src/main/</code></li>
+            <li><code>src/debug/</code> (build type)</li>
+            <li><code>src/full/</code> (flavor)</li>
+        </ul>
+    </li>
+    <li><p>For projects that use flavor dimensions, the build system uses one flavor source
+        directory per dimension. For example, to generate the <em>arm-demo-release</em> build
+        variant in the previous example, the build system uses:</p>
+        <ul>
+            <li><code>src/main/</code></li>
+            <li><code>src/release/</code> (build type)</li>
+            <li><code>src/demo/</code> (flavor - app type dimension)</li>
+            <li><code>src/arm/</code> (flavor - ABI dimension)</li>
+        </ul>
+    </li>
+</ul>
+
+<p class="note"><strong>Note:</strong> The build type and flavor source directories are optional,
+and Android Studio does not create these directories for you. The build system does not use them
+if they are not present.</p>
+
+<p>The source code from these directories is used together to generate the output for a build
+variant. You can have classes with the same name in different directories as long as those
+directories are not used together in the same variant. The exercise in this section shows you
+how to create different versions of the same activity class in different variants.</p>
+
+<p>The build system merges all the manifests into a single manifest, so each build variant
+can define different components or permissions in the final manifest.</p>
+
+<p>The build system merges all the resources from the all the source directories. If different
+folders contain resources with the same name for a build variant, the priority order is the
+following: build type resources override those from the product flavor, which override the
+resources in the main source directory.</p>
+
+<p class="note"><strong>Note:</strong> Build variants enable you to reuse common activities,
+application logic, and resources across different versions of your app.</p>
+
+<h4>Product flavors in BuildSystemExample</h4>
+
+<p>To create different versions of your app:</p>
+
+<ol>
+    <li>Define product flavors in the build file.</li>
+    <li>Create additional source directories for each flavor.</li>
+    <li>Add the flavor-specific sources to your project.</li>
+</ol>
+
+<p>The rest of this section walks you through these steps in detail using the
+<code>BuildSystemExample</code> project. You create two flavors of the
+<code>BuildSystemExample</code> app, a demo flavor and a full flavor. Both flavors share
+<code>MainActivity</code>, to which you add a new button to launch a new activity,
+<code>SecondActivity</code>. This new activity is different for each flavor, so you simulate a
+situation where the new activity would have more features in the full flavor than in the demo
+flavor. At the end of the exercise, you end up with two different APKs, one for each flavor.</p>
+
+<h4>Define product flavors in the build file</h4>
+
+<p>To define two product flavors, edit the build file for the app module to add the following
+configuration:</p>
+
+<pre>
+...
+android {
+    ...
+    defaultConfig { ... }
+    signingConfigs { ... }
+    buildTypes { ... }
+    productFlavors {
+        demo {
+            packageName "com.buildsystemexample.app.demo"
+            versionName "1.0-demo"
+        }
+        full {
+            packageName "com.buildsystemexample.app.full"
+            versionName "1.0-full"
+        }
+    }
+}
+...
+</pre>
+
+<p>The product flavor definitions support the same properties as the <code>defaultConfig</code>
+element. The base configuration for all flavors is specified in <code>defaultConfig</code>, and each
+flavor can override any value. The build file above assigns a different package name to each flavor:
+since each flavor definition creates a different app, they each need a distinct package name.</p>
+
+<p class="note"><strong>Note:</strong> To distribute your app using
+<a href="{@docRoot}google/play/publishing/multiple-apks.html">Multiple APK Support</a> in
+Google Play, assign the same package name to all variants and give each variant a different
+<code>versionCode</code>. To distribute different variants of your app as separate apps in Google
+Play, assign a different package name to each variant.</p>
+
+<h4>Add additional source directories for each flavor</h4>
+
+<p>Now you create source folders and add a <code>SecondActivity</code> to each flavor. To create
+the source directory structure for the demo flavor:</p>
+
+<ol>
+    <li>On the <em>Project</em> panel, expand <strong>BuildSystemExample</strong>, and then expand
+        the <strong>app</strong> directory.</li>
+    <li>Right click the <strong>src</strong> directory under <em>app</em> and select
+        <strong>New</strong> > <strong>Directory</strong>.</li>
+    <li>Enter "demo" as the name of the new directory and click <strong>OK</strong>.</li>
+    <li><p>Similarly, create the following directories:</p>
+        <ul>
+            <li><code>app/src/demo/java</code></li>
+            <li><code>app/src/demo/res</code></li>
+            <li><code>app/src/demo/res/layout</code></li>
+            <li><code>app/src/demo/res/values</code></li>
+        </ul>
+    </li>
+</ol>
+
+<p>The resulting directory structure looks like figure 5.</p>
+
+<img src="{@docRoot}images/tools/as-demoflavordirs.png" alt="" />
+<p class="img-caption"><strong>Figure 5.</strong> New source directories for the demo flavor.</p>
+
+<h4>Add a new activity to each flavor</h4>
+
+<p>To add <code>SecondActivity</code> to the <code>demo</code> flavor:</p>
+
+<ol>
+    <li>On the <em>Project</em> panel, right click on the <strong>app</strong> module and select
+        <strong>New</strong> > <strong>Activity</strong>.</li>
+    <li>Select <strong>Blank Activity</strong> and click <strong>Next</strong>.</li>
+    <li>Enter "SecondActivity" as the activity name.</li>
+    <li>Enter "com.buildsystemexample.app" as the package name and click
+        <strong>Finish</strong>.</li>
+    <li>Right click on the <strong>java</strong> directory under <em>app/src/demo</em> and select
+        <strong>New</strong> > <strong>Package</strong>.</li>
+    <li>Enter "com.buildsystemexample.app" as the package name and click <strong>OK</strong>.</li>
+    <li>Drag <strong>SecondActivity</strong> and drop it under the new package in
+        <em>app/src/demo/java</em>.</li>
+    <li>Accept the default values and click <strong>Refactor</strong>.</li>
+</ol>
+
+<p>To add the layout for <code>SecondActivity</code> and a strings resource to the demo flavor:</p>
+
+<ol>
+    <li>Drag <strong>activity_second.xml</strong> from <em>app/src/main/res/layout</em> and drop it
+        inside <em>app/src/demo/res/layout</em>.</li>
+    <li>Accept the default values on the window that appears and click <code>OK</code>.</li>
+    <li>Copy <strong>strings.xml</strong> from <em>app/src/main/res</em> into
+        <em>app/src/demo/res</em>.</li>
+    <li><p>Replace the contents of the new copy of <code>strings.xml</code> with the
+        following:</p>
+        <p><pre>
+&lt;?xml version="1.0" encoding="utf-8"?>
+&lt;resources>
+    &lt;string name="hello_world">Demo version only.&lt;/string>
+&lt;/resources>
+</pre></p>
+    </li>
+</ol>
+
+<p>Now you add source folders and <code>SecondActivity</code> to the full flavor by making a copy
+of the <code>demo</code> flavor:</p>
+
+<ol>
+    <li>On the <em>Project</em> panel, right click on the <strong>demo</strong> directory under
+        <em>app/src</em> and select <strong>Copy</strong>.</li>
+    <li>Right-click on the <strong>src/</strong> directory under <em>app/</em> and select
+        <strong>Paste</strong>.</li>
+    <li>On the window that appears, enter "full" as the new name and click <strong>OK</strong>.</li>
+    <li><p>Replace the contents of <strong>strings.xml</strong> under <em>src/full/res/values</em>
+        with the following:</p>
+        <p><pre>
+&lt;?xml version="1.0" encoding="utf-8"?>
+&lt;resources>
+    &lt;string name="hello_world">This is the full version!&lt;/string>
+&lt;/resources>
+</pre></p>
+    </li>
+</ol>
+
+<p class="note"><strong>Note:</strong> From this point on, you could develop
+<code>SecondActivity</code> independently inside each
+flavor. You can add more features to this activity in the <code>full</code> flavor.</p>
+
+<p>To work on files from a particular flavor, click on <strong>Build Variants</strong> on the left
+of the IDE window and select the flavor you want to modify in the <em>Build Variants</em> panel,
+as shown in figure 5. Android Studio may show errors in source files from flavors other than the
+one selected in the <em>Build Variants</em> panel, but this does not affect the outcome of the
+build.</p>
+
+<img src="{@docRoot}images/tools/as-buildvariants.png" alt="" />
+<p class="img-caption"><strong>Figure 6.</strong> The Build Variants panel.</p>
+
+<h4>Launch a flavor-specific activity from the main activity</h4>
+
+<p>Since the flavor-specific activity (<code>SecondActivity</code>) has the same package name and
+activity name in both flavors, you can launch it from the main activity, which is common to all
+flavors. To modify the main activity:</p>
+
+<ol>
+    <li><p>Edit <code>activity_main.xml</code> and add a new button to
+        <code>MainActivity</code>:</p>
+        <p><pre>
+&lt;LinearLayout ...>
+    ...
+    &lt;Button
+        android:id="@+id/button2"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/button2"
+        android:onClick="onButton2Clicked"/>
+&lt;/LinearLayout>
+</pre></p>
+    </li>
+    <li>Click on the areas marked in red in the layout file and press <strong>Alt</strong>+
+        <strong>Enter</strong>. Follow the suggestions from Android Studio to add a new string
+        resource with value “Open Second Activity” and an <code>onButton2Clicked</code> method to
+        <code>MainActivity</code>.</li>
+    <li><p>Add the following code to the <code>onButton2Clicked</code> method of
+        <code>MainActivity</code>:</p>
+        <p><pre>
+public void onButton2Clicked(View view) {
+    Intent intent = new Intent(this, SecondActivity.class);
+    startActivity(intent);
+}
+</pre></p>
+    </li>
+    <li><p>Edit the app's manifest to include a reference to <code>SecondActivity</code>:</p>
+        <p><pre>
+&lt;manifest ...>
+    &lt;application ...>
+        ...
+        &lt;activity
+            android:name="com.buildsystemexample.app.SecondActivity"
+            android:label="@string/title_activity_second" >
+        &lt;/activity>
+    &lt;/application>
+&lt;/manifest>
+</pre></p>
+    </li>
+</ol>
+
+<h4>Build output</h4>
+
+<p>The <code>BuildSystemExample</code> app is now complete. To build it, invoke the
+<code>assemble</code> task from Android Studio or from the command line.</p>
+
+<p>The build generates an APK for each build variant:
+the <code>app/build/apk/</code> directory contains packages named
+<code>app-&lt;flavor>-&lt;buildtype>.apk</code>; for example, <code>app-full-release.apk</code> and
+<code>app-demo-debug.apk</code>.</p>
+
+
+<h2 id="reference">Reference</h2>
+
+<p>The build system is very flexible and has more features than those described here. For a
+complete reference, see the
+<a href="http://tools.android.com/tech-docs/new-build-system/user-guide">Android Plugin for Gradle
+User Guide</a>.</p>
diff --git a/docs/html/sdk/installing/studio-debug.jd b/docs/html/sdk/installing/studio-debug.jd
new file mode 100644
index 0000000..7e2efe3
--- /dev/null
+++ b/docs/html/sdk/installing/studio-debug.jd
@@ -0,0 +1,346 @@
+page.title=Debugging with Android Studio
+
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+<h2>In this document</h2>
+<ol>
+  <li><a href="#runDebug">Run your App in Debug Mode</a></li>
+  <li><a href="#systemLog">Use the System Log</a>
+    <ol>
+      <li><a href="#systemLogWrite">Write log messages in your code</a></li>
+      <li><a href="#systemLogView">View the system log</a></li>
+    </ol>
+  </li>
+  <li><a href="#breakPoints">Work with Breakpoints</a>
+    <ol>
+        <li><a href="#breakPointsView">View and configure breakpoints</a></li>
+        <li><a href="#breakPointsDebug">Debug your app with breakpoints</a></li>
+    </ol>
+  </li>
+  <li><a href="#deviceMonitor">Analyze Runtime Metrics to Optimize your App</a></li>
+  <li><a href="#screenCap">Capture Screenshots and Videos</a></li>
+</ol>
+<h2>See also</h2>
+<ul>
+<li><a href="{@docRoot}sdk/installing/studio-tips.html">
+Android Studio Tips and Tricks</a></li>
+<li><a href="{@docRoot}tools/debugging/index.html">Debugging</a></li>
+<li><a href="{@docRoot}tools/help/monitor.html">Device Monitor</a></li>
+<li><a href="{@docRoot}tools/debugging/ddms.html">Using DDMS</a></li>
+</div>
+</div>
+
+<p>Android Studio enables you to debug apps running on the emulator or on an Android device.
+With Android Studio, you can:</p>
+
+<ul>
+    <li>Select a device to debug your app on.</li>
+    <li>View the system log.</li>
+    <li>Set breakpoints in your code.</li>
+    <li>Examine variables and evaluate expressions at run time.</li>
+    <li>Run the debugging tools from the Android SDK.</li>
+    <li>Capture screenshots and videos of your app.</li>
+</ul>
+
+<p>To debug your app, Android Studio builds a debuggable version of your app, connects
+to a device or to the emulator, installs the app and runs it. The IDE shows the system log
+while your app is running and provides debugging tools to filter log messages, work with
+breakpoints, and control the execution flow.</p>
+
+
+<h2 id="runDebug">Run your App in Debug Mode</h2>
+
+<div class="figure" style="width:419px">
+    <img src="{@docRoot}images/tools/as-debugdevices.png" alt=""/>
+    <p class="img-caption"><strong>Figure 1.</strong> The Choose Device window enables you to
+    select a physical Android device or a virtual device to debug your app.</p>
+</div>
+
+<p>To run your app in debug mode, you build an APK signed with a debug key and install it on a
+physical Android device or on the Android emulator.
+To set up an Android device for development, see <a href="{@docRoot}tools/device.html">Using
+Hardware Devices</a>. For more information about the emulator provided by the Android SDK, see
+<a href="{@docRoot}tools/devices/emulator.html">Using the Emulator.</a></p>
+
+<p>To debug your app in Android Studio:</p>
+
+<ol>
+    <li>Open your project in Android Studio.</li>
+    <li>Click <strong>Debug</strong> <img src="{@docRoot}images/tools/as-debugbutton.png"
+        style="vertical-align:bottom;margin:0;height:22px"  alt=""/> in the toolbar.</li>
+    <li>On the <em>Choose Device</em> window, select a hardware device from the list or
+        choose a virtual device.</li>
+    <li>Click <strong>OK</strong>. Your app starts on the selected device.</li>
+</ol>
+
+<p>Figure 1 shows the <em>Choose Device</em> window. The list shows all the Android devices
+connected to your computer. Select <strong>Launch Emulator</strong> to use an Android virtual device
+instead. Click the ellipsis <img src="{@docRoot}images/tools/as-launchavdm.png"
+style="vertical-align:bottom;margin:0;height:19px" alt=""/> to open the
+<a href="{@docRoot}tools/devices/managing-avds.html">Android Virtual Device Manager</a>.</p>
+
+<p>Android Studio opens the <em>Debug</em> tool window when you debug your app. To open the
+<em>Debug</em> window manually, click <strong>Debug</strong>
+<img src="{@docRoot}images/tools/as-debugwindowbutton.png"
+alt="" style="vertical-align:bottom;margin:0;height:20px"/>.
+This window shows threads and variables in the <em>Debugger</em> tab, the device status in the
+<em>Console</em> tab, and the system log in the <em>Logcat</em> tab. The <em>Debug</em> tool
+window also provides other debugging tools covered in the following sections.</p>
+
+<img src="{@docRoot}images/tools/as-debugview.png" alt="" />
+<p class="img-caption"><strong>Figure 2.</strong> The Debug tool window in Android Studio showing
+the current thread and the object tree for a variable.</p>
+
+
+<h2 id="systemLog">Use the System Log</h2>
+
+<p>The system log shows system messages while you debug your app. These messages include
+information from apps running on the device. If you want to use the
+system log to debug your app, make sure your code writes log messages and prints the stack
+trace for exceptions while your app is in the development phase.</p>
+
+<h3 id="systemLogWrite">Write log messages in your code</h3>
+
+<p>To write log messages in your code, use the {@link android.util.Log} class. Log messages
+help you understand the execution flow by collecting the system debug output while you interact
+with your app. Log messages can tell you what part of your application failed. For more
+information about logging, see <a href="{@docRoot}tools/debugging/debugging-log.html">
+Reading and Writing Logs</a>.</p>
+
+<p>The following example shows how you might add log messages to determine if previous state
+information is available when your activity starts:</p>
+
+<pre>
+import android.util.Log;
+...
+public class MyActivity extends Activity {
+    private static final String TAG = MyActivity.class.getSimpleName();
+    ...
+    &#64;Override
+    public void onCreate(Bundle savedInstanceState) {
+        if (savedInstanceState != null) {
+            Log.d(TAG, "onCreate() Restoring previous state");
+            /* restore state */
+        } else {
+            Log.d(TAG, "onCreate() No saved state available");
+            /* initialize app */
+        }
+    }
+}
+</pre>
+
+<p>During development, your code can also catch exceptions and write the stack trace to the system
+log:</p>
+
+<pre>
+void someOtherMethod() {
+    try {
+        ...
+    } catch (SomeException e) {
+        Log.d(TAG, "someOtherMethod()", e);
+    }
+}
+</pre>
+
+<p class="note"><strong>Note:</strong> Remove debug log messages and stack trace print calls from
+your code when you are ready to publish your app. You could do this by setting a <code>DEBUG</code>
+flag and placing debug log messages inside conditional statements.</p>
+
+
+<h3 id="systemLogView">View the system log</h3>
+
+<p>Both the <em>Android DDMS</em> (Dalvik Debug Monitor Server) and the <em>Debug</em> tool windows
+show the system log; however, the <em>Android DDMS</em> tool window lets you view only log messages
+for a particular process. To view the system log on the <em>Android DDMS</em> tool window:</p>
+
+<ol>
+    <li>Start your app as described in <a href="#runDebug">Run your App in Debug Mode</a>.</li>
+    <li>Click <strong>Android</strong> <img src="{@docRoot}images/tools/as-android.png" alt=""
+        style="vertical-align:bottom;margin:0;height:20px"/> to open the <em>Android DDMS</em>
+        tool window.</li>
+    <li>If the system log is empty in the <em>Logcat view</em>, click <strong>Restart</strong>
+        <img src="{@docRoot}images/tools/as-restart.png" alt=""
+        style="vertical-align:bottom;margin:0;height:22px"/>.</li>
+</ol>
+
+<img src="{@docRoot}images/tools/as-ddmslog.png" alt="" />
+<p class="img-caption"><strong>Figure 4.</strong> The system log in the Android DDMS tool
+window.</p>
+
+<p>The <em>Android DDMS</em> tool window gives you access to some DDMS features from Android Studio.
+For more information about DDMS, see <a href="{@docRoot}tools/debugging/ddms.html">Using DDMS</a>.
+</p>
+
+<p>The system log shows messages from Android services and other Android apps. To filter the log
+messages to view only the ones you are interested in, use the tools in the <em>Android DDMS</em>
+window:</p>
+
+<ul>
+    <li>To show only log messages for a particular process, select the process in the
+        <em>Devices</em> view and then click <strong>Only Show Logcat from Selected
+        Process</strong> <img src="{@docRoot}images/tools/as-currentproc.png" alt=""
+        style="vertical-align:bottom;margin:0;height:20px"/>. If the <em>Devices</em> view
+        is not available, click <strong>Restore Devices View</strong>
+        <img src="{@docRoot}images/tools/as-showdevview.png" alt=""
+        style="vertical-align:bottom;margin:0;height:20px"/> on the right of the <em>Android
+        DDMS</em> tool window. This button is only visible when you hide the <em>Devices</em>
+        window.</li>
+    <li>To filter log messages by log level, select a level under <em>Log Level</em> on the top
+        of the <em>Android DDMS</em> window.</li>
+    <li>To show only log messages that contain a particular string, enter the string in the search
+        box and press <strong>Enter</strong>.</li>
+</ul>
+
+
+<h2 id="breakPoints">Work with Breakpoints</h2>
+
+<p>Breakpoints enable you to pause the execution of your app at a particular line of code, examine
+variables, evaluate expressions, and continue the execution line by line. Use breakpoints to
+determine the causes of run-time errors that you can't fix by looking at your code only. To debug
+your app using breakpoints:</p>
+
+<ol>
+    <li>Open the source file in which you want to set a breakpoint.</li>
+    <li>Locate the line where you want to set a breakpoint and click on it.</li>
+    <li>Click on the yellow portion of the side bar to the left of this line, as shown in figure 5.</li>
+    <li>Start your app as described in <a href="#runDebug">Run your App in Debug Mode</a>.</li>
+</ol>
+
+<p>Android Studio pauses the execution of your app when it reaches the breakpoint. You can then
+use the tools in the <em>Debug</em> tool window to identify the cause of the error.</p>
+
+<img src="{@docRoot}images/tools/as-breakpointline.png" alt="" />
+<p class="img-caption"><strong>Figure 5.</strong> A red dot appears next to the line when you set
+a breakpoint.</p>
+
+<h3 id="breakPointsView">View and configure breakpoints</h3>
+
+<p>To view all the breakpoints and configure breakpoint settings, click <strong>View
+Breakpoints</strong> <img src="{@docRoot}images/tools/as-viewbreakbutton.png" alt=""
+style="vertical-align:bottom;margin:0;height:20px"/> on the left side of the <em>Debug</em> tool
+window. The <em>Breakpoints</em> window appears, as shown in figure 6.</p>
+
+<img src="{@docRoot}images/tools/as-breakpointswindow.png" alt="" />
+<p class="img-caption"><strong>Figure 6.</strong> The Breakpoints window lists all the current
+breakpoints and includes behavior settings for each.</p>
+
+<p>The <em>Breakpoints</em> window lets you enable or disable each breakpoint from the
+list on the left. If a breakpoint is disabled, Android Studio does not pause your app when
+it hits that breakpoint. Select a breakpoint from the list to configure its settings.
+You can configure a breakpoint to be disabled at first and have the system enable it after a
+different breakpoint is hit. You can also configure whether a breakpoint should be disabled after
+it is hit. To set a breakpoint for any exception, select <strong>Exception Breakpoints</strong>
+in the list of breakpoints.</p>
+
+<h3 id="breakPointsDebug">Debug your app with breakpoints</h3>
+
+<p>After you set breakpoints in your code, click <strong>Rerun</strong>
+<img src="{@docRoot}images/tools/as-restart.png" alt=""
+style="vertical-align:bottom;margin:0;height:20px"/> to start the app again. When a breakpoint is
+hit, Android Studio pauses the app and highlights the breakpoint in the source code. The
+<em>Debug</em> tool window lets you examine variables and control the execution step by
+step:</p>
+
+<ul>
+    <li>
+        <p>To examine the object tree for a variable, expand it in the <em>Variables</em> view. If
+        the <em>Variables</em> view is not visible, click <strong>Restore Variables View</strong>
+        <img src="{@docRoot}images/tools/as-varviewbutton.png" alt=""
+        style="vertical-align:bottom;margin:0;height:20px"/>.</p>
+    </li>
+    <li>
+        <p>To evaluate an expression at the current execution point, click <strong>Evaluate
+        Expression</strong> <img src="{@docRoot}images/tools/as-evalexpbutton.png" alt=""
+        style="vertical-align:bottom;margin:0;height:20px"/>.</p>
+    </li>
+    <li>
+        <p>To advance to the next line in the code (without entering a method), click <strong>Step
+        Over</strong> <img src="{@docRoot}images/tools/as-stepoverbutton.png" alt=""
+        style="vertical-align:bottom;margin:0;height:20px"/>.</p>
+    </li>
+    <li>
+        <p>To advance to the first line inside a method call, click <strong>Step
+        Into</strong> <img src="{@docRoot}images/tools/as-stepintobutton.png" alt=""
+        style="vertical-align:bottom;margin:0;height:20px"/>.</p>
+    </li>
+    <li>
+        <p>To advance to the next line outside the current method, click <strong>Step
+        Out</strong> <img src="{@docRoot}images/tools/as-stepoutbutton.png" alt=""
+        style="vertical-align:bottom;margin:0;height:20px"/>.</p>
+    </li>
+    <li>
+        <p>To continue running the app normally, click <strong>Resume Program</strong>
+        <img src="{@docRoot}images/tools/as-resumeprogrambutton.png" alt=""
+        style="vertical-align:bottom;margin:0;height:20px"/>.</p>
+    </li>
+</ul>
+
+<img src="{@docRoot}images/tools/as-variablesview.png" alt="" />
+<p class="img-caption"><strong>Figure 7.</strong> The Variables view in the Debug tool window.</p>
+
+
+<h2 id="deviceMonitor">Analyze Runtime Metrics to Optimize your App</h2>
+
+<p>Even if your application does not generate runtime errors, this does not mean it is free of
+problems. You should also consider the following issues:</p>
+
+<ul>
+    <li>Does your app use memory efficiently?</li>
+    <li>Does your app generate unnecessary network traffic?</li>
+    <li>What methods should you focus your attention on to improve the performance of your app?</li>
+    <li>Does your app behave properly when the user receives a phone call or a message?</li>
+</ul>
+
+<p>The Android Device Monitor is a stand-alone tool with a graphical user interface for serveral
+Android application debugging and analysis tools, including the Dalvik Debug Monitor Server (DDMS).
+You can use the Android Device Monitor to analyze memory usage, profile methods,
+monitor network traffic and simulate incoming calls and messages.</p>
+
+<p>To open the Android Device Monitor from Android Studio, click
+<strong>Monitor</strong> <img src="{@docRoot}images/tools/as-monitorbutton.png" alt=""
+style="vertical-align:bottom;margin:0;height:20px"/> on the toolbar. The Android Device Monitor
+opens in a new window.</p>
+
+<p>For more information about the Android Device Monitor and DDMS, see
+<a href="{@docRoot}tools/help/monitor.html">Device Monitor</a> and
+<a href="{@docRoot}tools/debugging/ddms.html">Using DDMS</a>.</p>
+
+
+<h2 id="screenCap">Capture Screenshots and Videos</h2>
+
+<p>Android Studio enables you to capture a screenshot or a short video of the device screen
+while your app is running. Screenshots and videos are useful as promotional materials for your
+app, and you can also attach them to bug reports that you send to your development team.</p>
+
+<p>To take a screenshot of your app:</p>
+
+<ol>
+    <li>Start your app as described in <a href="#runDebug">Run your App in Debug Mode</a>.</li>
+    <li>Click <strong>Android</strong> <img src="{@docRoot}images/tools/as-android.png" alt=""
+        style="vertical-align:bottom;margin:0;height:20px"/> to open the <em>Android DDMS</em>
+        tool window.</li>
+    <li>Click <strong>Screen Capture</strong> <img src="{@docRoot}images/tools/as-capture.png"
+        style="vertical-align:bottom;margin:0;height:22px" alt=""/> on the left side of the
+        <em>Android DDMS</em> tool window.</li>
+    <li>Optional: To add a device frame around your screenshot, enable the <em>Frame screenshot</em>
+        option.</li>
+    <li>Click <strong>Save</strong>.</li>
+</ol>
+
+<p>To take a video recording of your app:</p>
+
+<ol>
+    <li>Start your app as described in <a href="#runDebug">Run your App in Debug Mode</a>.</li>
+    <li>Click <strong>Android</strong> <img src="{@docRoot}images/tools/as-android.png" alt=""
+        style="vertical-align:bottom;margin:0;height:20px"/> to open the <em>Android DDMS</em>
+        tool window.</li>
+    <li>Click <strong>Screen Record</strong> <img src="{@docRoot}images/tools/as-record.png"
+        style="vertical-align:bottom;margin:0;height:22px" alt=""/> on the left side of the
+        <em>Android DDMS</em> tool window.</li>
+    <li>Click <strong>Start Recording</strong>.</li>
+    <li>Interact with your app.</li>
+    <li>Click <strong>Stop Recording</strong>.</li>
+    <li>Enter a file name for the recording and click <strong>OK</strong>.</li>
+</ol>
\ No newline at end of file
diff --git a/docs/html/sdk/installing/studio.jd b/docs/html/sdk/installing/studio.jd
index 365ec1d..2ad5808 100644
--- a/docs/html/sdk/installing/studio.jd
+++ b/docs/html/sdk/installing/studio.jd
@@ -253,36 +253,36 @@
     <td>Windows</td>
     <td>
   <a onclick="return onDownload(this)" id="win-studio"
-      href="http://dl.google.com/android/studio/install/0.4.6/android-studio-bundle-133.1028713-windows.exe">
-      android-studio-bundle-133.1028713-windows.exe
+      href="http://dl.google.com/android/studio/install/0.5.2/android-studio-bundle-135.1078000-windows.exe">
+      android-studio-bundle-135.1078000-windows.exe
       </a>
     </td>
-    <td>519592042 bytes</td>
-    <td>9029c18738a75830786326d62c96d557</td>
+    <td>519082997 bytes</td>
+    <td>ac69889210c4d02ee3ccc1c0f3c5cf3c</td>
   </tr>
 
   <tr>
     <td><nobr>Mac OS X</nobr></td>
     <td>
   <a onclick="return onDownload(this)" id="mac-studio"
-    href="http://dl.google.com/android/studio/install/0.4.6/android-studio-bundle-133.1028713-mac.dmg">
-    android-studio-bundle-133.1028713-mac.dmg
+    href="http://dl.google.com/android/studio/install/0.5.2/android-studio-bundle-135.1078000-mac.dmg">
+    android-studio-bundle-135.1078000-mac.dmg
     </a>
     </td>
-    <td>497595811 bytes</td>
-    <td>eb2474e6d17537ddfa535e6fe8adcf0d</td>
+    <td>495989974 bytes</td>
+    <td>8c7b1ef376b8ca206c99823d9e8fd54d</td>
   </tr>
 
   <tr>
     <td>Linux</td>
     <td>
   <a onclick="return onDownload(this)" id="linux-studio"
-    href="http://dl.google.com/android/studio/install/0.4.6/android-studio-bundle-133.1028713-linux.tgz">
-    android-studio-bundle-133.1028713-linux.tgz
+    href="http://dl.google.com/android/studio/install/0.5.2/android-studio-bundle-135.1078000-linux.tgz">
+    android-studio-bundle-135.1078000-linux.tgz
     </a>
     </td>
-    <td>522177460 bytes</td>
-    <td>cc847dd6249b3033737dabe0377c8c66</td>
+    <td>520523870 bytes</td>
+    <td>689238d5e632fd236b13f9c6d49f0cb4</td>
   </tr>
   </table>
 
@@ -312,11 +312,6 @@
 </div>
 
 
-<p>Also note that due to the update to Android Gradle Plugin 0.6, you will encounter errors when opening
-existing projects. See the <a href="#Troubleshooting">Troubleshooting</a> notes below for
-information about how to resolve them.</p>
-
-
 <h2 id="Installing">Installing Android Studio</h2>
 <p>Android Studio requires JDK 6 or greater (JRE alone is not sufficient). To check if you
 have JDK installed (and which version), open a terminal and type <code>javac -version</code>.
@@ -430,6 +425,19 @@
 <div class="toggle-content opened">
   <p><a href="#" onclick="return toggleContent(this)">
     <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img"
+      alt=""/>Android Studio v0.5.2</a> <em>(May 2014)</em>
+  </p>
+
+  <div class="toggle-content-toggleme">
+  <ul>
+    <li>See <a href="http://tools.android.com/recent">tools.android.com</a> for a full list of changes.</li>
+  </ul>
+  </div>
+</div>
+
+<div class="toggle-content closed">
+  <p><a href="#" onclick="return toggleContent(this)">
+    <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
       alt=""/>Android Studio v0.4.6</a> <em>(March 2014)</em>
   </p>
 
@@ -478,8 +486,7 @@
     <li>Android Gradle plug-in updated to 0.5.0.
       <p class="caution"><strong>Caution:</strong> This new version is not backwards compatible.
       When opening a project that uses an older version of the plug-in, Studio will show an error
-      stating <strong>Gradle &lt;project_name&gt; project refresh failed.</strong> See <a
-      href="#Troubleshooting">Troubleshooting</a> below for details.</p>
+      stating <strong>Gradle &lt;project_name&gt; project refresh failed.</strong></p>
       <p>The updated Gradle plug-in includes the following changes:</p>
       <ul>
         <li>Fixed IDE model to contain the output file even if it's customized through the DSL. Also
@@ -553,65 +560,7 @@
 
 <h2 id="Troubleshooting">Troubleshooting</h2>
 
-
-<div class="figure" style="width:330px">
-<img src="{@docRoot}images/tools/studio_error_gradle5.png" width="330"/>
-<p class="img-caption"><strong>Figure 1.</strong> Error dialog when opening an existing project.</p>
-</div>
-
-<h3>Error: Gradle project refresh failed</h3>
-
-<p>Android Studio 0.2.0 has updated the Gradle plug-in to 0.5.0, which is not backwards compatible.
-When opening a project that uses an older version of the plug-in, Studio will display the error
-shown in figure 1 in the upper right corner of the IDE.
-To resolve the error, you must change the version of the Android Gradle plug-in to 0.5.0.</p>
-
-<ol>
-  <li>Click the link in the error dialog <strong>Search in build.gradle files</strong>. If the dialog
-is no longer visible, click <strong>Event Log</strong>
-<img src="{@docRoot}images/tools/studio_error_eventlog.png"
-style="vertical-align:bottom;margin:0;height:19px"/> in the bottom-right corner of the IDE,
-then click <strong>Search in build.gradle files</strong>.</li>
-  <li>Double-click the line under the <em>build.gradle</em> usage. For example:
-  <strong>classpath 'com.android.tools.build:gradle:0.4</strong>. This opens the project
-  <code>build.gradle</code> file.</li>
-  <li>Edit the <code>classpath</code> to change the gradle version to <code>0.5.+</code>.
-  For example:
-  <pre class="no-pretty-print">
-dependencies {
-  classpath 'com.android.tools.build:gradle:<strong>0.5.+</strong>'
-}
-</pre>
-  </li>
-  <li>Save the file and rebuild your project.</li>
-</ol>
-
-
-
-<div class="figure" style="width:330px">
-<img src="{@docRoot}images/tools/studio_error_supportlib.png" width="330"/>
-<p class="img-caption"><strong>Figure 2.</strong> Error dialog when creating a new project
-or opening a project using the support library.</p>
-</div>
-
-<h3>Error: Failed to import Gradle project</h3>
-
-<p>If, after updating to Android Studio 0.2.x and creating or opening a project, you receive an
-error stating <em>"Could not find any version that matches
-com.android.support:support-v4:13.0.+"</em>, then you must install the <strong>Android Support
-Repository</strong>. This was likely caused because you're pointing Android Studio to an external
-Android SDK location that does not have the new Maven repository included with Android Studio
-0.2.x. This new Maven repository is used by the new build system for the Support Library, instead
-of using the Support Library JAR files, so must be present in the SDK.</p>
-
-
-<ol>
-  <li>Open the <strong>Android SDK Manager</strong>.</li>
-  <li>Expand the <strong>Extras</strong> directory
-and install <strong>Android Support Repository</strong>.</li>
-</ol>
-
-<p>If you've encountered other problems in Android Studio, look at the following page
+<p>If you encounter problems in Android Studio, look at the following page
 for possible resolutions to known issues: <a href="http://tools.android.com/knownissues"
 >http://tools.android.com/knownissues</a>.</p>
 
@@ -650,7 +599,7 @@
   if (os) {
     /* set up primary ACE download button */
     $('#download-ide-button').show();
-    $('#download-ide-button').append("Download Android Studio <span class='small'>v0.4.6</span>"
+    $('#download-ide-button').append("Download Android Studio <span class='small'>v0.5.2</span>"
         + "<br/> <span class='small'>for " + os + "</span>");
     $('#download-ide-button').click(function() {return onDownload(this,true);}).attr('href', bundlename);
 
diff --git a/docs/html/sitemap.txt b/docs/html/sitemap.txt
index 9bff5d4..cd87d1c 100644
--- a/docs/html/sitemap.txt
+++ b/docs/html/sitemap.txt
@@ -17,8 +17,8 @@
 http://developer.android.com/google/index.html
 http://developer.android.com/distribute/googleplay/publish/index.html
 http://developer.android.com/distribute/googleplay/promote/index.html
-http://developer.android.com/distribute/googleplay/quality/index.html
-http://developer.android.com/distribute/googleplay/spotlight/index.html
+http://developer.android.com/distribute/essentials/quality/index.html
+http://developer.android.com/distribute/stories/index.html
 http://developer.android.com/distribute/open.html
 http://developer.android.com/about/versions/jelly-bean.html
 http://developer.android.com/support.html
@@ -64,9 +64,9 @@
 http://developer.android.com/design/building-blocks/dialogs.html
 http://developer.android.com/design/building-blocks/pickers.html
 http://developer.android.com/google/play-services/maps.html
-http://developer.android.com/distribute/googleplay/quality/tablet.html
-http://developer.android.com/distribute/googleplay/spotlight/tablets.html
-http://developer.android.com/distribute/googleplay/quality/core.html
+http://developer.android.com/distribute/essentials/quality/tablet.html
+http://developer.android.com/distribute/stories/tablets.html
+http://developer.android.com/distribute/essentials/quality/core.html
 http://developer.android.com/guide/topics/ui/notifiers/notifications.html
 http://developer.android.com/guide/topics/ui/dialogs.html
 http://developer.android.com/downloads/design/Android_Design_Downloads_20120823.zip
@@ -173,13 +173,13 @@
 http://developer.android.com/distribute/googleplay/about/visibility.html
 http://developer.android.com/distribute/googleplay/about/monetizing.html
 http://developer.android.com/distribute/googleplay/about/distribution.html
-http://developer.android.com/distribute/googleplay/publish/register.html
+http://developer.android.com/distribute/googleplay/start.html
 http://developer.android.com/distribute/googleplay/publish/console.html
-http://developer.android.com/distribute/googleplay/publish/preparing.html
-http://developer.android.com/distribute/googleplay/promote/linking.html
+http://developer.android.com/distribute/tools/launch-checklist.html
+http://developer.android.com/distribute/tools/promote/linking.html
 http://developer.android.com/distribute/googleplay/promote/badges.html
 http://developer.android.com/distribute/promote/device-art.html
-http://developer.android.com/distribute/googleplay/promote/brand.html
+http://developer.android.com/distribute/tools/promote/brand.html
 http://developer.android.com/distribute/googleplay/strategies/app-quality.html
 http://developer.android.com/google/play/billing/index.html
 http://developer.android.com/google/play/licensing/index.html
diff --git a/docs/html/support.jd b/docs/html/support.jd
index 63bed30..4271eee 100644
--- a/docs/html/support.jd
+++ b/docs/html/support.jd
@@ -1,6 +1,8 @@
 page.title=Developer Support
+page.type=about
 fullpage=1
-excludeFromSuggestions=true
+page.metaDescription=Resources available to help you report and resolve issues while you are developing apps for Android.
+page.image=/images/android-support-card.png
 @jd:body
 
 <div class="wrap" style="width:940px;">
diff --git a/docs/html/tools/device.jd b/docs/html/tools/device.jd
index a1fb817..e9caa44 100644
--- a/docs/html/tools/device.jd
+++ b/docs/html/tools/device.jd
@@ -30,9 +30,8 @@
 you don't yet have a device, check with the service providers in your area to determine which
 Android-powered devices are available.</p>
 
-<p>If you want a SIM-unlocked phone, then you might consider a Nexus phone. To find a place
-to purchase the Nexus S and other Android-powered devices, visit <a
-href="http://www.google.com/phone/detail/nexus-s">google.com/phone</a>.</p>
+<p>If you want a SIM-unlocked phone, then you might consider a Nexus phone. To purchase a
+Nexus phone, visit the <a href="https://play.google.com/store/devices">Google Play</a> store.</p>
 
 <p class="note"><strong>Note:</strong> When developing on a device, keep in mind that you should
 still use the <a
@@ -90,11 +89,11 @@
             <p>Use this format to add each vendor to the file:<br/>
               <code>SUBSYSTEM==&quot;usb&quot;, ATTR{idVendor}==&quot;0bb4&quot;, MODE=&quot;0666&quot;, GROUP=&quot;plugdev&quot;</code>
               <br /><br />
-              
+
               In this example, the vendor ID is for HTC. The <code>MODE</code>
 assignment specifies read/write permissions, and <code>GROUP</code> defines
 which Unix group  owns the device node. </p>
-            
+
             <p class="note"><strong>Note:</strong> The rule syntax
 may vary slightly depending on your  environment. Consult the <code>udev</code>
 documentation for your system as needed. For an overview of rule syntax, see
@@ -138,7 +137,7 @@
 
 <p>This table provides a reference to the vendor IDs needed in order to add USB
 device support on Linux. The USB Vendor ID is the value given to the
-<code>ATTR{idVendor}</code> property in the rules file, as described 
+<code>ATTR{idVendor}</code> property in the rules file, as described
 above.</p>
 
 <table>
@@ -193,6 +192,10 @@
     <td><code>12d1</code></td>
   </tr>
   <tr>
+    <td>Intel</td>
+    <td><code>8087</code></td>
+  </tr>
+  <tr>
     <td>K-Touch</td>
     <td><code>24e3</code></td>
   </tr>
diff --git a/docs/html/tools/publishing/preparing.jd b/docs/html/tools/publishing/preparing.jd
index 413b56e..7192aa8 100644
--- a/docs/html/tools/publishing/preparing.jd
+++ b/docs/html/tools/publishing/preparing.jd
@@ -22,7 +22,7 @@
     <ol>
       <li><a href="{@docRoot}tools/publishing/publishing_overview.html">Publishing Overview</a></li>
       <li><a href="{@docRoot}tools/publishing/app-signing.html">Signing Your Applications</a></li>
-      <li><a href="{@docRoot}distribute/googleplay/publish/preparing.html">Launch Checklist for Google Play</a></li>
+      <li><a href="{@docRoot}distribute/tools/launch-checklist.html">Launch Checklist for Google Play</a></li>
     </ol>
   </div>
 </div>
@@ -44,7 +44,7 @@
 <p>This document summarizes the main tasks you need to perform to prepare your application for
 release. The tasks that are described in this document apply to all Android applications regardless
 how they are released or distributed to users. If you are releasing your application through Google
-Play, you should also read <a href="{@docRoot}distribute/googleplay/publish/preparing.html">Publishing
+Play, you should also read <a href="{@docRoot}distribute/tools/launch-checklist.html">Publishing
 Checklist for Google Play</a> to be sure your release-ready application satisfies all Google Play
 requirements.</p>
 
@@ -353,7 +353,7 @@
 behaves correctly, you can release your application to users. For more information, see
 <a href="{@docRoot}tools/publishing/publishing_overview.html#publishing-release">Releasing Your
 Application to Users</a>. If you are publishing your application on Google Play, see
-<a href="{@docRoot}distribute/googleplay/publish/preparing.html">Launch Checklist
+<a href="{@docRoot}distribute/tools/launch-checklist.html">Launch Checklist
 for Google Play</a>.</p>
 
 
diff --git a/docs/html/tools/publishing/publishing_overview.jd b/docs/html/tools/publishing/publishing_overview.jd
index ea01e20..c4b3bdf 100644
--- a/docs/html/tools/publishing/publishing_overview.jd
+++ b/docs/html/tools/publishing/publishing_overview.jd
@@ -16,7 +16,7 @@
   </ol>
   <h2>See also</h2>
   <ol>
-    <li><a href="{@docRoot}distribute/googleplay/publish/preparing.html">Publishing on Google Play</a></li>
+    <li><a href="{@docRoot}distribute/tools/launch-checklist.html">Publishing on Google Play</a></li>
   </ol>
 </div>
 </div>
@@ -35,7 +35,7 @@
   </li>
 </ul>
 
-<p>Usually, you release your application through an application marketplace, such as <a href="{@docRoot}distribute/index.html">Google Play</a>.
+<p>Usually, you release your application through an application marketplace, such as <a href="{@docRoot}distribute/googleplay/index.html">Google Play</a>.
 However, you can also release applications by sending them directly to users or by letting users
 download them from your own website.</p>
 
@@ -157,7 +157,7 @@
   </li>
 </ul>
 
-<p>For information complete information, see <a href="{@docRoot}distribute/index.html">Google Play</a>.</p>
+<p>For information complete information, see <a href="{@docRoot}distribute/googleplay/index.html">Google Play</a>.</p>
 
 
 <h3 id="publishing-email">Releasing your application through email</h3>
diff --git a/docs/html/tools/publishing/versioning.jd b/docs/html/tools/publishing/versioning.jd
index a1cfb30..6d3ec2f 100644
--- a/docs/html/tools/publishing/versioning.jd
+++ b/docs/html/tools/publishing/versioning.jd
@@ -25,7 +25,7 @@
 
 <ol>
 <li><a href="{@docRoot}tools/publishing/preparing.html">Preparing to Publish Your Application</a></li>
-<li><a href="{@docRoot}distribute/googleplay/publish/preparing.html">Launch Checklist for Google Play</a></li>
+<li><a href="{@docRoot}distribute/tools/launch-checklist.html">Launch Checklist for Google Play</a></li>
 <li><a href="{@docRoot}guide/topics/manifest/manifest-intro.html">The AndroidManifest.xml File</a></li>
 </ol>
 
diff --git a/docs/html/tools/revisions/build-tools.jd b/docs/html/tools/revisions/build-tools.jd
index c3c83ef..d8abab0 100644
--- a/docs/html/tools/revisions/build-tools.jd
+++ b/docs/html/tools/revisions/build-tools.jd
@@ -77,6 +77,26 @@
 <div class="toggle-content opened">
   <p><a href="#" onclick="return toggleContent(this)">
     <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img"
+      alt=""/>Build Tools, Revision 19.1.0</a> <em>(May 2014)</em>
+  </p>
+  <div class="toggle-content-toggleme">
+
+    <dl>
+      <dt>General Notes:</dt>
+      <dd>
+        <ul>
+          <li>Added <code>zipalign</code> to the Build Tools.</li>
+          <li>Modified <code>aapt</code> to ignore XML files that fail to compile.</li>
+        </ul>
+      </dd>
+    </dl>
+
+  </div>
+</div>
+
+<div class="toggle-content closed">
+  <p><a href="#" onclick="return toggleContent(this)">
+    <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
       alt=""/>Build Tools, Revision 19.0.3</a> <em>(March 2014)</em>
   </p>
   <div class="toggle-content-toggleme">
diff --git a/docs/html/tools/sdk/eclipse-adt.jd b/docs/html/tools/sdk/eclipse-adt.jd
index 7d20d5e..124e58d 100644
--- a/docs/html/tools/sdk/eclipse-adt.jd
+++ b/docs/html/tools/sdk/eclipse-adt.jd
@@ -53,10 +53,49 @@
 <p>For a summary of all known issues in ADT, see <a
 href="http://tools.android.com/knownissues">http://tools.android.com/knownissues</a>.</p>
 
-
 <div class="toggle-content opened">
   <p><a href="#" onclick="return toggleContent(this)">
     <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img"
+      alt=""/>ADT 22.6.3</a> <em>(April 2014)</em>
+  </p>
+
+  <div class="toggle-content-toggleme">
+<dl>
+  <dt>Dependencies:</dt>
+
+  <dd>
+    <ul>
+      <li>Java 1.6 or higher is required.</li>
+      <li>Eclipse Indigo (Version 3.7.2) or higher is required.</li>
+      <li>This version of ADT is designed for use with
+        <a href="{@docRoot}tools/sdk/tools-notes.html">SDK Tools r22.6.3</a>.
+        If you haven't already installed SDK Tools r22.6.3 into your SDK, use the
+        Android SDK Manager to do so.</li>
+    </ul>
+  </dd>
+
+  <dt>General Notes:</dt>
+  <dd>
+    <ul>
+      <li>Fixed a problem where the AVD manager allowed creating Android Wear virtual devices
+          with a target API Level lower than 19.</li>
+      <li>Fixed the description of Android Wear system images in the SDK Manager.</li>
+    </ul>
+  </dd>
+
+  <dt>Known Issues:</dt>
+  <dd>
+    <p>When you create an Android Wear virtual device in the AVD manager, a target API Level
+       lower than 19 may be selected by default. Make sure you select the target API Level 19
+       when creating Android Wear virtual devices.</p>
+  </dd>
+</dl>
+</div>
+</div>
+
+<div class="toggle-content closed">
+  <p><a href="#" onclick="return toggleContent(this)">
+    <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
       alt=""/>ADT 22.6.2</a> <em>(March 2014)</em>
   </p>
 
@@ -78,6 +117,11 @@
   <dt>General Notes:</dt>
   <dd>
     <ul>
+      <li><p>Changed the URL for the Android Developer Tools update site to require HTTPS.</p>
+          <p class="note"><strong>Note:</strong> If you are
+          <a href="{@docRoot}sdk/installing/installing-adt.html">updating ADT</a>, make sure
+          you use HTTPS in the URL for the Android Developer Tools update site.</p>
+      </li>
       <li>Fixed a problem where Eclipse was non-responsive for a few seconds after opening
           an XML file. (<a href="http://b.android.com/67084">Issue 67084</a>)</li>
       <li>Fixed a problem where the SDK Manager threw a <code>NullPointerException</code> after
@@ -88,7 +132,6 @@
           <code>drawable-large-*</code> directories.</li>
       <li>Fixed a problem with Nexus 5 Android virtual devices created from the command line
           where the SD card file system was read-only.</li>
-      <li>Changed the URL for the Android Developer Tools Update Site from HTTP to HTTPS.</li>
     </ul>
   </dd>
 </dl>
diff --git a/docs/html/tools/sdk/ndk/index.jd b/docs/html/tools/sdk/ndk/index.jd
index a22dc90..0ac1881 100644
--- a/docs/html/tools/sdk/ndk/index.jd
+++ b/docs/html/tools/sdk/ndk/index.jd
@@ -245,8 +245,8 @@
   but it always increases your app complexity. In general, you should only use the NDK
   if it is essential to your app&mdash;never because you simply prefer to program in C/C++.</p>
 
-  <p>Typical good candidates for the NDK are self-contained, CPU-intensive operations that don't
-  allocate much memory, such as signal processing, physics simulation, and so on. When examining
+  <p>Typical good candidates for the NDK are CPU-intensive workloads such as game engines,
+  signal processing, physics simulation, and so on. When examining
   whether or not you should develop in native code, think about your requirements and see if the
   Android framework APIs provide the functionality that you need.</p>
 
diff --git a/docs/html/tools/sdk/tools-notes.jd b/docs/html/tools/sdk/tools-notes.jd
index 14b5505..9b06a9d 100644
--- a/docs/html/tools/sdk/tools-notes.jd
+++ b/docs/html/tools/sdk/tools-notes.jd
@@ -28,6 +28,46 @@
 <div class="toggle-content opened">
   <p><a href="#" onclick="return toggleContent(this)">
     <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img"
+      alt=""/>SDK Tools, Revision 22.6.3</a> <em>(April 2014)</em>
+  </p>
+
+  <div class="toggle-content-toggleme">
+
+    <dl>
+    <dt>Dependencies:</dt>
+
+    <dd>
+      <ul>
+        <li>Android SDK Platform-tools revision 18 or later.</li>
+        <li>If you are developing in Eclipse with ADT, note that this version of SDK Tools is
+          designed for use with ADT 22.6.3 and later. If you haven't already, update your
+        <a href="{@docRoot}tools/sdk/eclipse-adt.html">ADT Plugin</a> to 22.6.3.</li>
+        <li>If you are developing outside Eclipse, you must have
+          <a href="http://ant.apache.org/">Apache Ant</a> 1.8 or later.</li>
+      </ul>
+    </dd>
+
+    <dt>General Notes:</dt>
+    <dd>
+      <ul>
+        <li>Fixed a problem where the AVD manager allowed creating Android Wear virtual devices
+            with a target API Level lower than 19.</li>
+        <li>Fixed the description of Android Wear system images in the SDK Manager.</li>
+      </ul>
+    </dd>
+
+    <dt>Known Issues:</dt>
+    <dd>
+      <p>When you create an Android Wear virtual device in the AVD manager, a target API Level
+         lower than 19 may be selected by default. Make sure you select the target API Level 19
+         when creating Android Wear virtual devices.</p>
+    </dd>
+  </div>
+</div>
+
+<div class="toggle-content closed">
+  <p><a href="#" onclick="return toggleContent(this)">
+    <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
       alt=""/>SDK Tools, Revision 22.6.2</a> <em>(March 2014)</em>
   </p>
 
diff --git a/docs/html/tools/support-library/index.jd b/docs/html/tools/support-library/index.jd
index 389238f..e905285 100644
--- a/docs/html/tools/support-library/index.jd
+++ b/docs/html/tools/support-library/index.jd
@@ -58,10 +58,36 @@
 
 <p>This section provides details about the Support Library package releases.</p>
 
-
 <div class="toggle-content opened">
   <p><a href="#" onclick="return toggleContent(this)">
     <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img" alt=""
+/>Android Support Library, revision 19.1.0</a> <em>(March 2014)</em>
+  </p>
+  <div class="toggle-content-toggleme">
+    <dl>
+      <dt>Changes for v4 support library:</dt>
+      <dd>
+        <ul>
+          <li>Added the {@link android.support.v4.widget.SwipeRefreshLayout} class,
+              which enables users to refresh the contents of a view with a vertical
+              swipe gesture.</li>
+          <li>Fixed accessibility issues with navigation drawers.</li>
+        </ul>
+      </dd>
+
+      <dt>Changes for v7 appcompat library:</dt>
+      <dd>
+        <ul>
+          <li>Fixed background issues with the action bar.</li>
+        </ul>
+      </dd>
+    </dl>
+  </div>
+</div>
+
+<div class="toggle-content closed">
+  <p><a href="#" onclick="return toggleContent(this)">
+    <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img" alt=""
 />Android Support Library, revision 19.0.1</a> <em>(December 2013)</em>
   </p>
   <div class="toggle-content-toggleme">
diff --git a/docs/html/tools/tools_toc.cs b/docs/html/tools/tools_toc.cs
index 382165c..b29b87c 100644
--- a/docs/html/tools/tools_toc.cs
+++ b/docs/html/tools/tools_toc.cs
@@ -36,6 +36,10 @@
               Tips and Tricks</a></li>
           <li><a href="<?cs var:toroot ?>sdk/installing/studio-layout.html">
               Using the Layout Editor</a></li>
+          <li><a href="<?cs var:toroot ?>sdk/installing/studio-build.html">
+              Building Your Project with Gradle</a></li>
+          <li><a href="<?cs var:toroot ?>sdk/installing/studio-debug.html">
+              Debugging with Android Studio</a></li>
           </ul>
       </li>
       <li><a href="<?cs var:toroot ?>sdk/exploring.html">
diff --git a/docs/html/training/basics/actionbar/styling.jd b/docs/html/training/basics/actionbar/styling.jd
index 1f76e03..4128a97 100644
--- a/docs/html/training/basics/actionbar/styling.jd
+++ b/docs/html/training/basics/actionbar/styling.jd
@@ -144,13 +144,13 @@
 &lt;resources>
     &lt;!-- the theme applied to the application or activity -->
     &lt;style name="CustomActionBarTheme"
-           parent="&#64;style/Theme.Holo.Light.DarkActionBar">
+           parent="&#64;android:style/Theme.Holo.Light.DarkActionBar">
         &lt;item name="android:actionBarStyle">&#64;style/MyActionBar&lt;/item>
     &lt;/style>
 
     &lt;!-- ActionBar styles -->
     &lt;style name="MyActionBar"
-           parent="&#64;style/Widget.Holo.Light.ActionBar.Solid.Inverse">
+           parent="&#64;android:style/Widget.Holo.Light.ActionBar.Solid.Inverse">
         &lt;item name="android:background">&#64;drawable/actionbar_background&lt;/item>
     &lt;/style>
 &lt;/resources>
diff --git a/docs/html/training/basics/firstapp/creating-project.jd b/docs/html/training/basics/firstapp/creating-project.jd
index 50485db..c4cb362 100644
--- a/docs/html/training/basics/firstapp/creating-project.jd
+++ b/docs/html/training/basics/firstapp/creating-project.jd
@@ -10,9 +10,9 @@
 
 
 <!-- This is the training bar -->
-<div id="tb-wrapper"> 
-<div id="tb"> 
- 
+<div id="tb-wrapper">
+<div id="tb">
+
 <h2>This lesson teaches you to</h2>
 
 <ol>
@@ -27,10 +27,10 @@
 SDK</a></li>
   <li><a href="{@docRoot}tools/projects/index.html">Managing Projects</a></li>
 </ul>
- 
- 
-</div> 
-</div> 
+
+
+</div>
+</div>
 
 <p>An Android project contains all the files that comprise the source code for your Android
 app. The Android SDK tools make it easy to start a new Android project with a set of
@@ -42,7 +42,7 @@
 
 <p class="note"><strong>Note:</strong> You should already have the Android SDK installed, and if
 you're using Eclipse, you should also have the <a href="{@docRoot}tools/sdk/eclipse-adt.html">ADT
-plugin</a> installed (version 21.0.0 or higher). If you don't have these, follow the guide to <a
+plugin</a> installed (version 22.6.2 or higher). If you don't have these, follow the guide to <a
 href="{@docRoot}sdk/installing/index.html">Installing the Android SDK</a> before you start this
 lesson.</p>
 
@@ -50,7 +50,7 @@
 <h2 id="Eclipse">Create a Project with Eclipse</h2>
 
 <ol>
-  <li>Click <strong>New</strong> <img src="{@docRoot}images/tools/eclipse-new.png" 
+  <li>Click <strong>New</strong> <img src="{@docRoot}images/tools/eclipse-new.png"
   style="vertical-align:baseline;margin:0" /> in the toolbar.</li>
   <li>In the window that appears, open the <strong>Android</strong> folder,
   select <strong>Android Application Project</strong>, and click <strong>Next</strong>.</li>
@@ -116,11 +116,11 @@
   <li>Now you can select an activity template from which to begin building your app.
     <p>For this project, select <strong>BlankActivity</strong> and click <strong>Next</strong>.</p>
   </li>
-  <li>Leave all the details for the activity in their default state and click 
+  <li>Leave all the details for the activity in their default state and click
     <strong>Finish</strong>.</li>
 </ol>
 
-<p>Your Android project is now a basic "Hello World" app that contains some default files. 
+<p>Your Android project is now a basic "Hello World" app that contains some default files.
 To run the app, continue to the <a href="running-app.html">next lesson</a>.</p>
 
 
@@ -155,7 +155,7 @@
 projects.</p></li>
 </ol>
 
-<p>Your Android project is now a basic "Hello World" app that contains some default files. 
+<p>Your Android project is now a basic "Hello World" app that contains some default files.
 To run the app, continue to the <a href="running-app.html">next lesson</a>.</p>
 
 <p class="note"><strong>Tip:</strong> Add the <code>platform-tools/</code> as well as the
diff --git a/docs/html/training/basics/firstapp/index.jd b/docs/html/training/basics/firstapp/index.jd
index 4c1a0dc3..1b49096 100644
--- a/docs/html/training/basics/firstapp/index.jd
+++ b/docs/html/training/basics/firstapp/index.jd
@@ -8,21 +8,21 @@
 
 @jd:body
 
-<div id="tb-wrapper"> 
-<div id="tb"> 
- 
-<h2>Dependencies and prerequisites</h2> 
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>Dependencies and prerequisites</h2>
 
 <ul>
   <li><a href="http://developer.android.com/sdk/index.html">Android SDK</a></li>
-  <li><a href="{@docRoot}tools/sdk/eclipse-adt.html">ADT Plugin</a> 20.0.0 or higher
+  <li><a href="{@docRoot}tools/sdk/eclipse-adt.html">ADT Plugin</a> 22.6.2 or higher
     (if you're using Eclipse)</li>
 </ul>
- 
-</div> 
-</div> 
- 
-<p>Welcome to Android application development!</p> 
+
+</div>
+</div>
+
+<p>Welcome to Android application development!</p>
 
 <p>This class teaches you how to build your first Android app. You’ll learn how to create an Android
 project and run a debuggable version of the app. You'll also learn some fundamentals of Android app
@@ -36,6 +36,10 @@
   <li>Download the latest SDK tools and platforms using the SDK Manager.</li>
 </ol>
 
+<p class="note"><strong>Note:</strong> Make sure you install the most recent versions of the ADT
+plugin and the Android SDK before you start this class. The procedures described in this class may
+not apply to earlier versions.</p>
+
 <p>If you haven't already done these tasks, start by downloading the
   <a href="{@docRoot}sdk/index.html">Android SDK</a> and following the install steps.
   Once you've finished the setup, you're ready to begin this class.</p>
diff --git a/docs/html/training/basics/firstapp/starting-activity.jd b/docs/html/training/basics/firstapp/starting-activity.jd
index 9aa25a3..27d2c10 100644
--- a/docs/html/training/basics/firstapp/starting-activity.jd
+++ b/docs/html/training/basics/firstapp/starting-activity.jd
@@ -10,9 +10,9 @@
 
 
 <!-- This is the training bar -->
-<div id="tb-wrapper"> 
-<div id="tb"> 
- 
+<div id="tb-wrapper">
+<div id="tb">
+
 <h2>This lesson teaches you to</h2>
 
 <ol>
@@ -30,10 +30,10 @@
   <li><a href="{@docRoot}sdk/installing/index.html">Installing the
 SDK</a></li>
 </ul>
- 
- 
-</div> 
-</div> 
+
+
+</div>
+</div>
 
 
 
@@ -151,7 +151,7 @@
 </pre>
 
 <p class="note"><strong>Note:</strong>
-You now need an import statement for <code>android.widget.EditText</code>. 
+You now need an import statement for <code>android.widget.EditText</code>.
 You'll define the <code>EXTRA_MESSAGE</code> constant in a moment.</p>
 
 <p>An {@link android.content.Intent} can carry a collection of various data types as key-value
@@ -212,7 +212,7 @@
 <p>To create a new activity using Eclipse:</p>
 
 <ol>
-  <li>Click <strong>New</strong> <img src="{@docRoot}images/tools/eclipse-new.png" 
+  <li>Click <strong>New</strong> <img src="{@docRoot}images/tools/eclipse-new.png"
   style="vertical-align:baseline;margin:0" /> in the toolbar.</li>
   <li>In the window that appears, open the <strong>Android</strong> folder
   and select <strong>Android Activity</strong>. Click <strong>Next</strong>.</li>
@@ -247,15 +247,19 @@
   <li>There's also an implementation of {@link android.app.Activity#onOptionsItemSelected
   onOptionsItemSelected()} which handles the behavior for the action bar's <em>Up</em> behavior.
   Keep this one the way it is.</li>
-  <li>There's also a <code>PlaceholderFragment</code> class that extends 
+  <li>There's also a <code>PlaceholderFragment</code> class that extends
 {@link android.app.Fragment}. You will not need this class in the final version of this
 activity.</li>
 </ul>
 
-<p>Fragments decompose application functionality and UI into reusable modules. For more 
-information on fragments, see the <a href="{@docRoot}guide/components/fragments.html">Fragments 
+<p>Fragments decompose application functionality and UI into reusable modules. For more
+information on fragments, see the <a href="{@docRoot}guide/components/fragments.html">Fragments
 API Guide</a>. The final version of this activity does not use fragments.</p>
 
+<p class="note"><strong>Note:</strong> Your activity may look different if you did not use
+the latest version of the ADT plugin. Make sure you install the latest version of the
+<a href="{@docRoot}tools/sdk/eclipse-adt.html">ADT plugin</a> to complete this tutorial.</p>
+
 <p>The {@code DisplayMessageActivity} class should now look like this:</p>
 
 <pre>
diff --git a/docs/html/training/basics/intents/sending.jd b/docs/html/training/basics/intents/sending.jd
index 30dc95a..2a4dae7 100644
--- a/docs/html/training/basics/intents/sending.jd
+++ b/docs/html/training/basics/intents/sending.jd
@@ -166,7 +166,7 @@
 starts in case you need to disable the feature that uses the intent before the user attempts to use
 it. If you know of a specific app that can handle the intent, you can also provide a link for the
 user to download the app (see how to <a
-href="{@docRoot}distribute/googleplay/promote/linking.html">link to your product on Google
+href="{@docRoot}distribute/tools/promote/linking.html">link to your product on Google
 Play</a>).</p>
 
 
diff --git a/docs/html/training/basics/supporting-devices/languages.jd b/docs/html/training/basics/supporting-devices/languages.jd
index 130848e..057103a 100644
--- a/docs/html/training/basics/supporting-devices/languages.jd
+++ b/docs/html/training/basics/supporting-devices/languages.jd
@@ -19,7 +19,7 @@
     </ol>
     <h2>You should also read</h2>
     <ul>
-    <li><a href="{@docRoot}distribute/googleplay/publish/localizing.html">Localization Checklist</a></li>
+    <li><a href="{@docRoot}distribute/tools/localization-checklist.html">Localization Checklist</a></li>
       <li><a href="{@docRoot}guide/topics/resources/localization.html">Localization with Resources</a></li>
     </ul>
   </div>
diff --git a/docs/html/training/basics/supporting-devices/platforms.jd b/docs/html/training/basics/supporting-devices/platforms.jd
index c38101a..60aaf6a 100644
--- a/docs/html/training/basics/supporting-devices/platforms.jd
+++ b/docs/html/training/basics/supporting-devices/platforms.jd
@@ -1,4 +1,5 @@
 page.title=Supporting Different Platform Versions
+page.metaDescription=Training on how to declare support for minimum and target API levels.
 parent.title=Supporting Different Devices
 parent.link=index.html
 
diff --git a/docs/html/training/design-navigation/multiple-sizes.jd b/docs/html/training/design-navigation/multiple-sizes.jd
index 26a5828..a0ce103 100644
--- a/docs/html/training/design-navigation/multiple-sizes.jd
+++ b/docs/html/training/design-navigation/multiple-sizes.jd
@@ -8,6 +8,10 @@
 next.title=Providing Descendant and Lateral Navigation
 next.link=descendant-lateral.html
 
+meta.tags="multiple screens"
+page.metaDescription=Designing an intuitive, effective navigation for tablets and other devices.
+page.image=/images/training/app-navigation-multiple-sizes-strategy-stack.png
+
 @jd:body
 
 <div id="tb-wrapper">
diff --git a/docs/html/training/game-controllers/controller-input.jd b/docs/html/training/game-controllers/controller-input.jd
index 2c50ae1..c9517ba 100644
--- a/docs/html/training/game-controllers/controller-input.jd
+++ b/docs/html/training/game-controllers/controller-input.jd
@@ -236,26 +236,33 @@
   </tr>
   <tr>
     <td>Start game in main menu, or pause/unpause during game</td>
-    <td>{@link android.view.KeyEvent#KEYCODE_BUTTON_START BUTTON_START}</td>
+    <td>{@link android.view.KeyEvent#KEYCODE_BUTTON_START BUTTON_START}<sup>*</sup></td>
   </tr>
   <tr>
     <td>Display menu</td>
-    <td>{@link android.view.KeyEvent#KEYCODE_BUTTON_SELECT BUTTON_SELECT} and
-{@link android.view.KeyEvent#KEYCODE_MENU}</td>
+    <td>{@link android.view.KeyEvent#KEYCODE_BUTTON_SELECT BUTTON_SELECT}<sup>*</sup>
+      and {@link android.view.KeyEvent#KEYCODE_MENU}<sup>*</sup></td>
   </tr>
   <tr>
     <td>Same as Android <em>Back</em></td>
-    <td>{@link android.view.KeyEvent#KEYCODE_BUTTON_B BUTTON_B}<sup>*</sup> and
-{@link android.view.KeyEvent#KEYCODE_BACK KEYCODE_BACK}</td>
+    <td>{@link android.view.KeyEvent#KEYCODE_BACK KEYCODE_BACK}</td>
+  </tr>
+  <tr>
+    <td>Navigate back to a previous item in a menu</td>
+    <td>{@link android.view.KeyEvent#KEYCODE_BUTTON_B BUTTON_B}<sup>**</sup></td>
   </tr>
   <tr>
     <td>Confirm selection, or perform primary game action</td>
-    <td>{@link android.view.KeyEvent#KEYCODE_BUTTON_A BUTTON_A}<sup>*</sup> and
+    <td>{@link android.view.KeyEvent#KEYCODE_BUTTON_A BUTTON_A}<sup>**</sup> and
 {@link android.view.KeyEvent#KEYCODE_DPAD_CENTER DPAD_CENTER}</td>
   </tr>
 </table>
 <p>
-<em>* This could be the opposite button (A/B), depending on the locale that
+<em>* Your game should not rely on the presence of the Start, Select, or Menu
+  buttons.</em>
+</p>
+<p>
+<em>** This could be the opposite button (A/B), depending on the locale that
 you are supporting.</em>
 </p>
 
diff --git a/docs/html/training/multiscreen/index.jd b/docs/html/training/multiscreen/index.jd
index 2d34b28..8eff246 100644
--- a/docs/html/training/multiscreen/index.jd
+++ b/docs/html/training/multiscreen/index.jd
@@ -1,5 +1,6 @@
 page.title=Designing for Multiple Screens
 page.tags="tablet","tv","fragments","support"
+page.metaDescription=Training on how to add intuitive, effective navigation for tablets and other devices.
 
 trainingnavtop=true
 startpage=true
diff --git a/docs/html/training/multiscreen/screendensities.jd b/docs/html/training/multiscreen/screendensities.jd
index 7d6ff44..7817830 100644
--- a/docs/html/training/multiscreen/screendensities.jd
+++ b/docs/html/training/multiscreen/screendensities.jd
@@ -1,4 +1,7 @@
 page.title=Supporting Different Densities
+page.metaDescription=Providing sets of layouts and drawable resources for specific ranges of device screens.
+meta.tags="multiple screens"
+
 parent.title=Designing for Multiple Screens
 parent.link=index.html
 
diff --git a/docs/html/training/notify-user/display-progress.jd b/docs/html/training/notify-user/display-progress.jd
index 2b2b3ae..c00576c 100644
--- a/docs/html/training/notify-user/display-progress.jd
+++ b/docs/html/training/notify-user/display-progress.jd
@@ -80,6 +80,7 @@
     setProgress(0, 0, false)}. For example:
 </p>
 <pre>
+int id = 1;
 ...
 mNotifyManager =
         (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
@@ -100,7 +101,7 @@
                     // state
                     mBuilder.setProgress(100, incr, false);
                     // Displays the progress bar for the first time.
-                    mNotifyManager.notify(0, mBuilder.build());
+                    mNotifyManager.notify(id, mBuilder.build());
                         // Sleeps the thread, simulating an operation
                         // that takes time
                         try {
@@ -114,7 +115,7 @@
             mBuilder.setContentText("Download complete")
             // Removes the progress bar
                     .setProgress(0,0,false);
-            mNotifyManager.notify(ID, mBuilder.build());
+            mNotifyManager.notify(id, mBuilder.build());
         }
     }
 // Starts the thread by calling the run() method in its Runnable
@@ -157,7 +158,7 @@
 // percentage, and "determinate" state
 mBuilder.setProgress(100, incr, false);
 // Issues the notification
-mNotifyManager.notify(0, mBuilder.build());
+mNotifyManager.notify(id, mBuilder.build());
 </pre>
 <p>
     Replace the lines you've found with the following lines. Notice that the third parameter
@@ -169,7 +170,7 @@
  // Sets an activity indicator for an operation of indeterminate length
 mBuilder.setProgress(0, 0, true);
 // Issues the notification
-mNotifyManager.notify(0, mBuilder.build());
+mNotifyManager.notify(id, mBuilder.build());
 </pre>
 <p>
     The resulting indicator is shown in figure 2:
diff --git a/docs/html/training/notify-user/navigation.jd b/docs/html/training/notify-user/navigation.jd
index ac4689a..fc950131 100644
--- a/docs/html/training/notify-user/navigation.jd
+++ b/docs/html/training/notify-user/navigation.jd
@@ -95,6 +95,7 @@
         {@link android.app.Activity}. For example:
 </p>
 <pre>
+int id = 1;
 ...
 Intent resultIntent = new Intent(this, ResultActivity.class);
 TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
diff --git a/docs/html/wear/design/index.html b/docs/html/wear/design/index.html
deleted file mode 100644
index 9952490..0000000
--- a/docs/html/wear/design/index.html
+++ /dev/null
@@ -1,607 +0,0 @@
-<!DOCTYPE html>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-<html>
-<head>
-
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
-<meta name="viewport" content="width=device-width" />
-
-<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
-<title>Design Principles of Android Wear | Android Developers</title>
-
-<!-- STYLESHEETS -->
-<link rel="stylesheet"
-href="//fonts.googleapis.com/css?family=Roboto:light,regular,medium,thin,italic,mediumitalic,bold" title="roboto">
-<link href="/assets/css/default.css" rel="stylesheet" type="text/css">
-
-
-
-<!-- JAVASCRIPT -->
-<script src="//www.google.com/jsapi" type="text/javascript"></script>
-<script src="/assets/js/android_3p-bundle.js" type="text/javascript"></script>
-<script type="text/javascript">
-  var toRoot = "/";
-  var metaTags = [];
-  var devsite = false;
-</script>
-<script src="/assets/js/docs.js" type="text/javascript"></script>
-
-<script type="text/javascript">
-  var _gaq = _gaq || [];
-  _gaq.push(['_setAccount', 'UA-5831155-1']);
-  _gaq.push(['_trackPageview']);
-
-  (function() {
-    var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
-    ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
-    var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
-  })();
-</script>
-</head>
-
-<body class="gc-documentation 
-  " itemscope itemtype="http://schema.org/Article">
-
-
-  
-<a name="top"></a>
-
-    <!-- Header -->
-    <div id="header">
-        <div class="wrap" id="header-wrap">
-          <div class="col-3 logo-wear">
-          <a href="/wear/index.html">
-            <img src="/wear/images/android-wear.png" height="16" alt="Android Wear" />
-          </a>
-          </div>
-
-
-	<div class="col-8" style="margin:0"><h1 style="margin:1px 0 0 20px;padding:0;line-height:16px;
-  color:#666;font-weight:100;font-size:24px;">Developer Preview</h1></div>
-            
-
-          <!-- New Search -->
-          <div class="menu-container">
-            <div class="moremenu">
-	        <div id="more-btn"></div>
-	    </div>
-  <div class="morehover" id="moremenu">
-    <div class="top"></div>
-    <div class="mid">
-      <div class="header">Links</div>
-      <ul>
-        <li><a href="https://play.google.com/apps/publish/">Google Play Developer Console</a></li>
-        <li><a href="http://android-developers.blogspot.com/">Android Developers Blog</a></li>
-        <li><a href="/about/index.html">About Android</a></li>
-      </ul>
-      <div class="header">Android Sites</div>
-      <ul>
-        <li><a href="http://www.android.com">Android.com</a></li>
-        <li class="active"><a>Android Developers</a></li>
-        <li><a href="http://source.android.com">Android Open Source Project</a></li>
-      </ul>
-      
-      
-      
-        <div class="header">Language</div>
-          <div id="language" class="locales">
-            <select name="language" onChange="changeLangPref(this.value, true)">
-                <option value="en">English</option>
-                <option value="es">Español</option>
-                <option value="ja">日本語</option>
-                <option value="ko">한국어</option>
-                <option value="ru">Русский</option>
-                <option value="zh-cn">中文 (中国)</option>
-                <option value="zh-tw">中文 (台灣)</option>
-            </select>
-          </div>
-        <script type="text/javascript">
-          <!--
-          loadLangPref();
-            //-->
-        </script>
-      
-      
-
-
-      <br class="clearfix" />
-    </div><!-- end mid -->
-    <div class="bottom"></div>
-  </div><!-- end morehover -->
-
-  <div class="search" id="search-container">
-    <div class="search-inner">
-      <div id="search-btn"></div>
-      <div class="left"></div>
-      <form onsubmit="return submit_search()">
-        <input id="search_autocomplete" type="text" value="" autocomplete="off" name="q"
-onfocus="search_focus_changed(this, true)" onblur="search_focus_changed(this, false)"
-onkeydown="return search_changed(event, true, '/')" 
-onkeyup="return search_changed(event, false, '/')" />
-      </form>
-      <div class="right"></div>
-        <a class="close hide">close</a>
-        <div class="left"></div>
-        <div class="right"></div>
-    </div>
-  </div><!--  end search -->
-
-  <div class="search_filtered_wrapper reference">
-    <div class="suggest-card reference no-display">
-      <ul class="search_filtered">
-      </ul>
-    </div>
-  </div>
-
-  <div class="search_filtered_wrapper docs">
-    <div class="suggest-card dummy no-display">&nbsp;</div>
-    <div class="suggest-card develop no-display">
-      <ul class="search_filtered">
-      </ul>
-      <div class="child-card guides no-display">
-      </div>
-      <div class="child-card training no-display">
-      </div>
-      <div class="child-card samples no-display">
-      </div>
-    </div>
-    <div class="suggest-card design no-display">
-      <ul class="search_filtered">
-      </ul>
-    </div>
-    <div class="suggest-card distribute no-display">
-      <ul class="search_filtered">
-      </ul>
-    </div>
-  </div><!-- end search_filtered_wrapper -->
-
-  </div>
-  <!-- end menu_container -->
-
-
-        </div><!-- end header-wrap -->
-    </div>
-    <!-- /Header -->
-
-
-  <div id="searchResults" class="wrap" style="display:none;">
-          <h2 id="searchTitle">Results</h2>
-          <div id="leftSearchControl" class="search-control">Loading...</div>
-  </div>
-
-  
-
-  
-
-  <div class="wrap clearfix" id="body-content">
-    <div class="col-4" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
-      <div id="devdoc-nav" class="scroll-pane">
-<a class="totop" href="#top" data-g-event="left-nav-top">to top</a>
-
-<ul id="nav">
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/wear/preview/start.html">Get Started
-      </a></div>
-  </li>
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/wear/design/user-interface.html">UI Overview
-      </a></div>
-  </li>
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/wear/design/index.html">Design Principles
-      </a></div>
-  </li>
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/wear/notifications/creating.html">Creating Notifications for Android Wear
-      </a></div>
-  </li>
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/wear/notifications/remote-input.html">Receiving Voice Input from a Notification
-      </a></div>
-  </li>
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/wear/notifications/pages.html">Adding Pages to a Notification
-      </a></div>
-  </li>
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/wear/notifications/stacks.html">Stacking Notifications
-      </a></div>
-  </li>
-
-  <li class="nav-section">
-    <div class="nav-section-header"><a href="/reference/android/preview/support/package-summary.html">Notification Reference</a></div>
-    <ul class="tree-list-children">
-<li class="nav-section">
-<div class="nav-section-header-ref"><span class="tree-list-subtitle package" title="android.preview.support.v4.app">android.preview.support.v4.app</span></div>
-  <ul>
-<li><a href="/reference/android/preview/support/v4/app/NotificationManagerCompat.html">NotificationManagerCompat</a></li>
-  </ul>
-</li>
-
-<li class="nav-section">
-<div class="nav-section-header-ref"><span class="tree-list-subtitle package" title="android.preview.support.wearable.notifications">android.preview.support.wearable.notifications</span></div>
-<ul>
-
-<li><a href="/reference/android/preview/support/wearable/notifications/RemoteInput.html">RemoteInput</a></li>
-<li><a href="/reference/android/preview/support/wearable/notifications/RemoteInput.Builder.html" >RemoteInput.Builder</a></li>
-
-<li><a href="/reference/android/preview/support/wearable/notifications/WearableNotifications.html">WearableNotifications</a></li>
-
-<li><a href="/reference/android/preview/support/wearable/notifications/WearableNotifications.Action.html">WearableNotifications.Action</a></li>
-
-<li><a href="/reference/android/preview/support/wearable/notifications/WearableNotifications.Action.Builder.html">WearableNotifications.Action.Builder</a></li>
-
-<li><a href="/reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html">WearableNotifications.Builder</a></li>
-	</ul>
-  </li>
-</ul>
-</li>
-
-
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/wear/license.html">License Agreement</a></div>
-  </li>
-
-
-</ul>
-
-        
-
-      </div>
-    </div> <!-- end side-nav -->
-    <script>
-      $(document).ready(function() {
-        scrollIntoView("devdoc-nav");
-        });
-    </script>
-
-
-
-
-<div class="col-12" id="doc-col" >
-
-
-  
-    
-      
-        <h1 itemprop="name" >Design Principles of Android Wear</h1>
-      
-    
-  
-
-
-  
-  <div id="jd-content">
-
-
-    <div class="jd-descr" itemprop="articleBody">
-    <style>
-h3 {
- padding:30px 0 10px;
-}
-</style>
-<p>
-Android wearables provide just the right information at just the right time, allowing you to be connected to the virtual world and present in the real world.</p>
-
-<img src="/wear/images/05_images.png" height="200" width="169" style="float:right;clear:right;margin:0 0 60px 60px" />
-
-<p>Here you’ll find some guidelines for designing great user experiences on the Android Wear
-platform. Designing for Android Wear is substantially different than designing for phones or
-tablets, so we’ll start by describing how your content can work in tandem with the overall
-Android Wear vision. To better understand the user experience on Android Wear, also be sure
-to read the <a href="/wear/design/user-interface.html">UI Overview</a>.</p>
-
-
-<img src="/wear/images/02_notifications.png" height="200" width="169" style="float:right;clear:right;margin:0 0 20px 60px" />
-
-
-
-<p>Android Wear experiences are:</p>
-
-<ul>
-  <li><strong>Contextually aware and smart.</strong> These devices bring a new level of awareness to computing. Rather than requiring attention and input from users, Android wearables are aware of their situation and state, and helpfully display the right information at the right time. <em>Timely, relevant, specific</em>.</li>
-
-  <li><strong>Glanceable.</strong> Wearable devices are used all throughout the day, even when they sit in our peripheral vision. Effective apps provide the maximum payload of information with a minimum of fuss, optimized to provide tiny snippets of relevant information throughout the day. <em>Short, sharp, immediate.</em></li>
-
-  <li><strong>Zero/low interaction.</strong> Staying true to the strengths afforded by a smaller form factor, Android Wear focuses on simple interactions, only requiring input by the user when absolutely necessary. Most inputs are based around touch swipes or voice, and inputs requiring fine-grained motor skills are avoided. <em>Gestural, simple, fast.</em></li>
-
-  <li><strong>Helpful.</strong> Android Wear is like a great personal assistant: it knows you and your preferences, it only interrupts you when absolutely necessary, and it’s always on hand to provide a ready answer. <em>Efficient, respectful, responsive.</em></li>
-</ul>
-
-
-<p>
-By providing a smart connection to the rest of the world while respecting the user’s attention, Android Wear feels personal and global, simple and smart, unobtrusive and ever-ready. Notifications that respect these principles will feel most at home in the overall Android Wear experience.
-</p>
-
-
-
-<h2 id="Notifications" style="clear:both">Notification UI Patterns</h2>
-
-<p>Android notifications appear as cards in the main stream and form the core of the Android Wear experience. Many of the main <a href="http://developer.android.com/design/patterns/notifications.html">Android Design guidelines for notifications</a> apply in Android Wear. Be respectful of users' attention and aware of how unnecessary interruptions will reflect on your application’s reputation.</p>
-
-<p>Omit needless text from your notifications. Design for glanceability, not reading. Use words and phrases, not sentences. Show, don't tell: where possible use simple icons, glyphs, and visualizations to convey your message.</p>
-<img src="/wear/images/circle_message2.png" height="200" style="float:right;clear:right;margin:0 0 20px 60px" />
-
-<p>In some cases, particularly with messaging applications, cards will contain dynamic content which may not fit on a single screen. In these cases the content will be automatically truncated to fit on the card and the user may tap to expand, so the full message should be provided.</p>
-
-<p>Notification priority should reflect the urgency of your notification, with only time-sensitive notifications carrying a high priority. Active notifications – that is, those that cause the device to vibrate – should only be used in cases that need the user's urgent attention or action (e.g. a time-based reminder, a message from a friend). Non-urgent notifications (e.g. a transit times card, daily pedometer count, social network updates) should be silently added to the card stream.</p>
-
-
-
-
-<h3 id="NotifictionActions" style="clear:both">Actions</h3>
-
-<img src="/wear/images/circle_message2_reply.png" height="200" style="float:right;clear:right;margin:0 0 20px 40px" />
-
-<p>Actions appear to the right of your notification, allowing the user to act on your notification. Up to three actions are permitted. The most-used action should be placed first, so that it is a single swipe away from your content.</p>
-
-<p>Actions consist of an icon and a caption. Icons should be PNG files, white on transparent background, 64 × 64 DP. Captions should be verb-driven and short, and will be automatically truncated at one line.</p>
-
-<p>Actions are optional. Many useful notifications will not need to include actions at all.</p>
-
-<p>For developer details about action buttons, see <a href="/wear/notifications/creating.html">Creating
-Notifications for Android Wear</a>.</p>
-
-
-
-
-
-
-<h3 id="Images" style="clear:both">Images</h3>
-
-<img src="/wear/images/circle_badge_B.png" height="200" style="float:right;clear:right;margin:0 0 20px 40px" />
-
-
-<p>Images appear behind cards in the stream, providing context and additional glanceability. Your image should support the core message of the notification; for example, a card about a sports team could include the team color and logo; a message from a contact should display that person's profile photo.</p>
-
-<p>Bear in mind that the card will partially cover the lower part of the image. Images should be at least 320 × 320 pixels at hdpi. Image backgrounds move when horizontally swiped, so landscape-oriented images work better on notifications that include pages or actions.</p>
-
-<p>To add large images, use <code><a href="/reference/android/support/v4/app/NotificationCompat.Builder.html#setLargeIcon(android.graphics.Bitmap)">setLargeIcon()</a></code> with any notification, as
-shown in <a href="/wear/notifications/creating.html">Creating
-Notifications for Android Wear</a>.</p>
-
-
-
-
-
-<h3 id="AppIcons" style="clear:both">Application Icons</h3>
-
-<img src="/wear/images/07_appicons.png" height="200" style="float:right;margin:0 0 20px 60px" />
-
-<p>Your application’s launcher icon will be automatically placed on the card, identifying your notification. Do not use the notification title or background image to identify or brand your application. Instead, allow your icon to identify itself and focus on delivering a clear, succinct message in the card and image. You can choose not to display this icon using
- <a href="/reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html#setHintHideIcon(boolean)"><code>setHintHideIcon()</code></a>.
-</p>
-
-
-
-
-
-
-
-<h3 id="NotificationPages" style="clear:both">Pages</h3>
-
-<p>Pages are additional cards that can appear to the right of your main card in the stream. If your core message is longer than a short snippet, do not sacrifice glanceability by packing a lot of information into your primary notification. Instead, use pages to provide additional content.</p>
-
-<img src="/wear/images/08_pages.png" height="200" style="float:left;margin:0 0 20px 0px" />
-<img src="/wear/images/09_pages.png" height="200" style="float:left;margin:0 0 20px 60px" />
-<img src="/wear/images/10_pages.png" height="200" style="float:left;margin:0 0 20px 60px" />
-
-<p style="clear:left">Pages appear immediately to the right of the main notification card. They are typically used to provide additional details or alternate views of the main card’s content. For example:</p>
-<ul>
-  <li>A current weather card might provide an additional page showing a three-day forecast.</li>
-  <li>A next train departure card might provide an additional page showing subsequent departures times.</li>
-  <li>A daily step count card might provide an additional page showing the same measurement in calories and distance.</li>
-</ul>
-
-<p>There is no imposed limit on the number of pages you may add. However, notifications that provide actions should show no more than three pages to ensure that the actions remain easily accessible.</p>
-
-<p>Pages are optional. Many useful notifications will not need to include pages at all.</p>
-
-<p>For developer details about pages, see
-described in <a href="/wear/notifications/pages.html">Adding
-Pages to a Notification</a>.</p>
-
-
-
-
-
-<h3 id="NotificationStacks" style="clear:both">Notification Stacks</h3>
-
-<img src="/wear/images/11_bundles_B.png" height="200" style="float:right;margin:0 0 20px 60px" />
-<img src="/wear/images/11_bundles_A.png" height="200" style="float:right;margin:0 0 20px 60px" />
-
-<p>Stacks may be used to collect multiple notifications from the same application into a single stack of cards. Whereas pages are used to provide additional detail on a single notification, stacks are used to collect multiple sibling notifications together. A stack may be expanded by the user to access each individual card contained within.</p>
-
-<p>Stacks are a way of adding multiple useful notifications without overwhelming the user’s stream. If your application may produce multiple concurrent notifications, consider combining them into a stack.</p>
-
-<p>Each notification within a stack can contain separate pages and separate actions that are relevant to that specific notification. The user can access these actions after expanding that notification's card within the stack.</p>
-
-<p>For developer details about stacks, see
-described in <a href="/wear/notifications/stacks.html">Stacking
-Notifications</a>.</p>
-
-
-
-
-
-
-<h3 id="VoiceReplies" style="clear:both">Voice Replies</h3>
-
-
-<img src="/wear/images/circle_voice_B.png" height="200" style="float:right;margin:0 0 20px 40px" />
-<img src="/wear/images/circle_voice_A.png" height="200" style="float:right;margin:0 0 20px 40px" />
-
-<p>Voice replies are primarily used by messaging applications to provide a hands-free way of dictating a short message. You can also provide a up to five suggested replies or “canned responses” that are useful in a wide range of cases. These canned responses can be tapped by the user, allowing for a fast method of sending simple replies in cases where speaking may not be desirable.</p>
-
-<p>You should attempt to cover a range of simple, neutral replies in your choices. Longer voice replies may be automatically truncated in the Voice reply UI.</p>
-
-<p>For developer details about enabling voice replies, see
-described in <a href="/wear/notifications/remote-input.html">Receiving Voice Input from
-a Notification</a>.</p>
-
-    </div>
-
-      <div class="content-footer layout-content-row"
-                    itemscope itemtype="http://schema.org/SiteNavigationElement">
-        <div class="layout-content-col col-9" style="padding-top:4px">
-          
-            <div class="g-plusone" data-size="medium"></div>
-          
-        </div>
-        
-        <div class="paging-links layout-content-col col-4">
-          
-        </div>
-        
-      </div>
-
-      
-      
-
-  </div> <!-- end jd-content -->
-
-<div id="footer" class="wrap" >
-        
-
-  <div id="copyright">
-    
-  Except as noted, this content is 
-  licensed under <a href="http://creativecommons.org/licenses/by/2.5/">
-  Creative Commons Attribution 2.5</a>. For details and 
-  restrictions, see the <a href="/license.html">Content 
-  License</a>.
-  </div>
-
-
-  <div id="footerlinks">
-    
-  <p>
-    <a href="/about/index.html">About Android</a>&nbsp;&nbsp;|&nbsp;
-    <a href="/legal.html">Legal</a>&nbsp;&nbsp;|&nbsp;
-    <a href="/support.html">Support</a>
-  </p>
-  </div>
-
-</div> <!-- end footer -->
-</div><!-- end doc-content -->
-
-</div> <!-- end body-content --> 
-
-
-
-
-
-
-<!-- Start of Tag -->
-<script type="text/javascript">
-var axel = Math.random() + "";
-var a = axel * 10000000000000;
-document.write('<iframe src="https://2507573.fls.doubleclick.net/activityi;src=2507573;type=other026;cat=googl348;ord=' + a + '?" width="1" height="1" frameborder="0" style="display:none"></iframe>');
-</script>
-<noscript>
-<iframe src="https://2507573.fls.doubleclick.net/activityi;src=2507573;type=other026;cat=googl348;ord=1?" width="1" height="1" frameborder="0" style="display:none"></iframe>
-</noscript>
-<!-- End of Tag -->
-</body>
-</html>
-
-
-
diff --git a/docs/html/wear/design/index.jd b/docs/html/wear/design/index.jd
new file mode 100644
index 0000000..247cc87
--- /dev/null
+++ b/docs/html/wear/design/index.jd
@@ -0,0 +1,173 @@
+page.title=Design Principles of Android Wear
+
+@jd:body
+
+<style>
+h3 {
+ padding:30px 0 10px;
+}
+</style>
+<p>
+Android wearables provide just the right information at just the right time, allowing you to be connected to the virtual world and present in the real world.</p>
+
+<img src="{@docRoot}wear/images/05_images.png" height="200" width="169" style="float:right;clear:right;margin:0 0 60px 60px" />
+
+<p>Here you’ll find some guidelines for designing great user experiences on the Android Wear
+platform. Designing for Android Wear is substantially different than designing for phones or
+tablets, so we’ll start by describing how your content can work in tandem with the overall
+Android Wear vision. To better understand the user experience on Android Wear, also be sure
+to read the <a href="{@docRoot}wear/design/user-interface.html">UI Overview</a>.</p>
+
+
+<img src="{@docRoot}wear/images/02_notifications.png" height="200" width="169" style="float:right;clear:right;margin:0 0 20px 60px" />
+
+
+
+<p>Android Wear experiences are:</p>
+
+<ul>
+  <li><strong>Contextually aware and smart.</strong> These devices bring a new level of awareness to computing. Rather than requiring attention and input from users, Android wearables are aware of their situation and state, and helpfully display the right information at the right time. <em>Timely, relevant, specific</em>.</li>
+
+  <li><strong>Glanceable.</strong> Wearable devices are used all throughout the day, even when they sit in our peripheral vision. Effective apps provide the maximum payload of information with a minimum of fuss, optimized to provide tiny snippets of relevant information throughout the day. <em>Short, sharp, immediate.</em></li>
+
+  <li><strong>Zero/low interaction.</strong> Staying true to the strengths afforded by a smaller form factor, Android Wear focuses on simple interactions, only requiring input by the user when absolutely necessary. Most inputs are based around touch swipes or voice, and inputs requiring fine-grained motor skills are avoided. <em>Gestural, simple, fast.</em></li>
+
+  <li><strong>Helpful.</strong> Android Wear is like a great personal assistant: it knows you and your preferences, it only interrupts you when absolutely necessary, and it’s always on hand to provide a ready answer. <em>Efficient, respectful, responsive.</em></li>
+</ul>
+
+
+<p>
+By providing a smart connection to the rest of the world while respecting the user’s attention, Android Wear feels personal and global, simple and smart, unobtrusive and ever-ready. Notifications that respect these principles will feel most at home in the overall Android Wear experience.
+</p>
+
+
+
+<h2 id="Notifications" style="clear:both">Notification UI Patterns</h2>
+
+<p>Android notifications appear as cards in the main stream and form the core of the Android Wear experience. Many of the main <a href="http://developer.android.com/design/patterns/notifications.html">Android Design guidelines for notifications</a> apply in Android Wear. Be respectful of users' attention and aware of how unnecessary interruptions will reflect on your application’s reputation.</p>
+
+<p>Omit needless text from your notifications. Design for glanceability, not reading. Use words and phrases, not sentences. Show, don't tell: where possible use simple icons, glyphs, and visualizations to convey your message.</p>
+<img src="{@docRoot}wear/images/circle_message2.png" height="200" style="float:right;clear:right;margin:0 0 20px 60px" />
+
+<p>In some cases, particularly with messaging applications, cards will contain dynamic content which may not fit on a single screen. In these cases the content will be automatically truncated to fit on the card and the user may tap to expand, so the full message should be provided.</p>
+
+<p>Notification priority should reflect the urgency of your notification, with only time-sensitive notifications carrying a high priority. Active notifications – that is, those that cause the device to vibrate – should only be used in cases that need the user's urgent attention or action (e.g. a time-based reminder, a message from a friend). Non-urgent notifications (e.g. a transit times card, daily pedometer count, social network updates) should be silently added to the card stream.</p>
+
+
+
+
+<h3 id="NotifictionActions" style="clear:both">Actions</h3>
+
+<img src="{@docRoot}wear/images/circle_message2_reply.png" height="200" style="float:right;clear:right;margin:0 0 20px 40px" />
+
+<p>Actions appear to the right of your notification, allowing the user to act on your notification. Up to three actions are permitted. The most-used action should be placed first, so that it is a single swipe away from your content.</p>
+
+<p>Actions consist of an icon and a caption. Icons should be PNG files, white on transparent
+background, 32 × 32 dp (with 8 dp padding), as specified in the <a
+href="/design/style/iconography.html#action-bar">Iconography</a> design guide for action bar
+icons. Captions should be verb-driven and short, and will be automatically truncated at one line.
+</p>
+
+<p>Actions are optional. Many useful notifications will not need to include actions at all.</p>
+
+<p>For developer details about action buttons, see <a href="{@docRoot}wear/notifications/creating.html">Creating
+Notifications for Android Wear</a>.</p>
+
+
+
+
+
+
+<h3 id="Images" style="clear:both">Images</h3>
+
+<img src="{@docRoot}wear/images/circle_badge_B.png" height="200" style="float:right;clear:right;margin:0 0 20px 40px" />
+
+
+<p>Images appear behind cards in the stream, providing context and additional glanceability. Your image should support the core message of the notification; for example, a card about a sports team could include the team color and logo; a message from a contact should display that person's profile photo.</p>
+
+<p>Bear in mind that the card will partially cover the lower part of the image. Images should
+be sized as appropriate for the notification appearance on handsets, which is 64 x 64 dp. Image backgrounds move when horizontally swiped, so landscape-oriented images work better on notifications that include pages or actions.</p>
+
+<p>To add large images, use {@link android.support.v4.app.NotificationCompat.Builder#setLargeIcon
+setLargeIcon()} with any notification, as
+shown in <a href="{@docRoot}wear/notifications/creating.html">Creating
+Notifications for Android Wear</a>.</p>
+
+
+
+
+
+<h3 id="AppIcons" style="clear:both">Application Icons</h3>
+
+<img src="{@docRoot}wear/images/07_appicons.png" height="200" style="float:right;margin:0 0 20px 60px" />
+
+<p>Your application’s launcher icon will be automatically placed on the card, identifying your notification. Do not use the notification title or background image to identify or brand your application. Instead, allow your icon to identify itself and focus on delivering a clear, succinct message in the card and image. You can choose not to display this icon using
+ <a href="/reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html#setHintHideIcon(boolean)"><code>setHintHideIcon()</code></a>.
+</p>
+
+
+
+
+
+
+
+<h3 id="NotificationPages" style="clear:both">Pages</h3>
+
+<p>Pages are additional cards that can appear to the right of your main card in the stream. If your core message is longer than a short snippet, do not sacrifice glanceability by packing a lot of information into your primary notification. Instead, use pages to provide additional content.</p>
+
+<img src="{@docRoot}wear/images/08_pages.png" height="200" style="float:left;margin:0 0 20px 0px" />
+<img src="{@docRoot}wear/images/09_pages.png" height="200" style="float:left;margin:0 0 20px 60px" />
+<img src="{@docRoot}wear/images/10_pages.png" height="200" style="float:left;margin:0 0 20px 60px" />
+
+<p style="clear:left">Pages appear immediately to the right of the main notification card. They are typically used to provide additional details or alternate views of the main card’s content. For example:</p>
+<ul>
+  <li>A current weather card might provide an additional page showing a three-day forecast.</li>
+  <li>A next train departure card might provide an additional page showing subsequent departures times.</li>
+  <li>A daily step count card might provide an additional page showing the same measurement in calories and distance.</li>
+</ul>
+
+<p>There is no imposed limit on the number of pages you may add. However, notifications that provide actions should show no more than three pages to ensure that the actions remain easily accessible.</p>
+
+<p>Pages are optional. Many useful notifications will not need to include pages at all.</p>
+
+<p>For developer details about pages, see
+described in <a href="{@docRoot}wear/notifications/pages.html">Adding
+Pages to a Notification</a>.</p>
+
+
+
+
+
+<h3 id="NotificationStacks" style="clear:both">Notification Stacks</h3>
+
+<img src="{@docRoot}wear/images/11_bundles_B.png" height="200" style="float:right;margin:0 0 20px 60px" />
+<img src="{@docRoot}wear/images/11_bundles_A.png" height="200" style="float:right;margin:0 0 20px 60px" />
+
+<p>Stacks may be used to collect multiple notifications from the same application into a single stack of cards. Whereas pages are used to provide additional detail on a single notification, stacks are used to collect multiple sibling notifications together. A stack may be expanded by the user to access each individual card contained within.</p>
+
+<p>Stacks are a way of adding multiple useful notifications without overwhelming the user’s stream. If your application may produce multiple concurrent notifications, consider combining them into a stack.</p>
+
+<p>Each notification within a stack can contain separate pages and separate actions that are relevant to that specific notification. The user can access these actions after expanding that notification's card within the stack.</p>
+
+<p>For developer details about stacks, see
+described in <a href="{@docRoot}wear/notifications/stacks.html">Stacking
+Notifications</a>.</p>
+
+
+
+
+
+
+<h3 id="VoiceReplies" style="clear:both">Voice Replies</h3>
+
+
+<img src="{@docRoot}wear/images/circle_voice_B.png" height="200" style="float:right;margin:0 0 20px 40px" />
+<img src="{@docRoot}wear/images/circle_voice_A.png" height="200" style="float:right;margin:0 0 20px 40px" />
+
+<p>Voice replies are primarily used by messaging applications to provide a hands-free way of dictating a short message. You can also provide a up to five suggested replies or “canned responses” that are useful in a wide range of cases. These canned responses can be tapped by the user, allowing for a fast method of sending simple replies in cases where speaking may not be desirable.</p>
+
+<p>You should attempt to cover a range of simple, neutral replies in your choices. Longer voice replies may be automatically truncated in the Voice reply UI.</p>
+
+<p>For developer details about enabling voice replies, see
+described in <a href="{@docRoot}wear/notifications/remote-input.html">Receiving Voice Input from
+a Notification</a>.</p>
diff --git a/docs/html/wear/design/user-interface.html b/docs/html/wear/design/user-interface.html
deleted file mode 100644
index c23d79c..0000000
--- a/docs/html/wear/design/user-interface.html
+++ /dev/null
@@ -1,498 +0,0 @@
-<!DOCTYPE html>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-<html>
-<head>
-
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
-<meta name="viewport" content="width=device-width" />
-
-<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
-<title>UI Overview | Android Developers</title>
-
-<!-- STYLESHEETS -->
-<link rel="stylesheet"
-href="//fonts.googleapis.com/css?family=Roboto:light,regular,medium,thin,italic,mediumitalic,bold" title="roboto">
-<link href="/assets/css/default.css" rel="stylesheet" type="text/css">
-
-
-
-<!-- JAVASCRIPT -->
-<script src="//www.google.com/jsapi" type="text/javascript"></script>
-<script src="/assets/js/android_3p-bundle.js" type="text/javascript"></script>
-<link rel="stylesheet" type="text/css" href="/wear/css/wear.css">
-<script type="text/javascript">
-  var toRoot = "/";
-  var metaTags = [];
-  var devsite = false;
-</script>
-<script src="/assets/js/docs.js" type="text/javascript"></script>
-
-<script type="text/javascript">
-  var _gaq = _gaq || [];
-  _gaq.push(['_setAccount', 'UA-5831155-1']);
-  _gaq.push(['_trackPageview']);
-
-  (function() {
-    var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
-    ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
-    var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
-  })();
-</script>
-</head>
-
-<body class="gc-documentation 
-  " itemscope itemtype="http://schema.org/Article">
-
-
-  
-<a name="top"></a>
-
-    <!-- Header -->
-    <div id="header">
-        <div class="wrap" id="header-wrap">
-          <div class="col-3 logo-wear">
-          <a href="/wear/index.html">
-            <img src="/wear/images/android-wear.png" height="16" alt="Android Wear" />
-          </a>
-          </div>
-
-
-	<div class="col-8" style="margin:0"><h1 style="margin:1px 0 0 20px;padding:0;line-height:16px;
-  color:#666;font-weight:100;font-size:24px;">Developer Preview</h1></div>
-            
-
-          <!-- New Search -->
-          <div class="menu-container">
-            <div class="moremenu">
-	        <div id="more-btn"></div>
-	    </div>
-  <div class="morehover" id="moremenu">
-    <div class="top"></div>
-    <div class="mid">
-      <div class="header">Links</div>
-      <ul>
-        <li><a href="https://play.google.com/apps/publish/">Google Play Developer Console</a></li>
-        <li><a href="http://android-developers.blogspot.com/">Android Developers Blog</a></li>
-        <li><a href="/about/index.html">About Android</a></li>
-      </ul>
-      <div class="header">Android Sites</div>
-      <ul>
-        <li><a href="http://www.android.com">Android.com</a></li>
-        <li class="active"><a>Android Developers</a></li>
-        <li><a href="http://source.android.com">Android Open Source Project</a></li>
-      </ul>
-      
-      
-      
-        <div class="header">Language</div>
-          <div id="language" class="locales">
-            <select name="language" onChange="changeLangPref(this.value, true)">
-                <option value="en">English</option>
-                <option value="es">Español</option>
-                <option value="ja">日本語</option>
-                <option value="ko">한국어</option>
-                <option value="ru">Русский</option>
-                <option value="zh-cn">中文 (中国)</option>
-                <option value="zh-tw">中文 (台灣)</option>
-            </select>
-          </div>
-        <script type="text/javascript">
-          <!--
-          loadLangPref();
-            //-->
-        </script>
-      
-      
-
-
-      <br class="clearfix" />
-    </div><!-- end mid -->
-    <div class="bottom"></div>
-  </div><!-- end morehover -->
-
-  <div class="search" id="search-container">
-    <div class="search-inner">
-      <div id="search-btn"></div>
-      <div class="left"></div>
-      <form onsubmit="return submit_search()">
-        <input id="search_autocomplete" type="text" value="" autocomplete="off" name="q"
-onfocus="search_focus_changed(this, true)" onblur="search_focus_changed(this, false)"
-onkeydown="return search_changed(event, true, '/')" 
-onkeyup="return search_changed(event, false, '/')" />
-      </form>
-      <div class="right"></div>
-        <a class="close hide">close</a>
-        <div class="left"></div>
-        <div class="right"></div>
-    </div>
-  </div><!--  end search -->
-
-  <div class="search_filtered_wrapper reference">
-    <div class="suggest-card reference no-display">
-      <ul class="search_filtered">
-      </ul>
-    </div>
-  </div>
-
-  <div class="search_filtered_wrapper docs">
-    <div class="suggest-card dummy no-display">&nbsp;</div>
-    <div class="suggest-card develop no-display">
-      <ul class="search_filtered">
-      </ul>
-      <div class="child-card guides no-display">
-      </div>
-      <div class="child-card training no-display">
-      </div>
-      <div class="child-card samples no-display">
-      </div>
-    </div>
-    <div class="suggest-card design no-display">
-      <ul class="search_filtered">
-      </ul>
-    </div>
-    <div class="suggest-card distribute no-display">
-      <ul class="search_filtered">
-      </ul>
-    </div>
-  </div><!-- end search_filtered_wrapper -->
-
-  </div>
-  <!-- end menu_container -->
-
-
-        </div><!-- end header-wrap -->
-    </div>
-    <!-- /Header -->
-
-
-  <div id="searchResults" class="wrap" style="display:none;">
-          <h2 id="searchTitle">Results</h2>
-          <div id="leftSearchControl" class="search-control">Loading...</div>
-  </div>
-
-  
-
-  
-
-  <div class="wrap clearfix" id="body-content">
-    <div class="col-4" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
-      <div id="devdoc-nav" class="scroll-pane">
-<a class="totop" href="#top" data-g-event="left-nav-top">to top</a>
-
-<ul id="nav">
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/wear/preview/start.html">Get Started
-      </a></div>
-  </li>
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/wear/design/user-interface.html">UI Overview
-      </a></div>
-  </li>
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/wear/design/index.html">Design Principles
-      </a></div>
-  </li>
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/wear/notifications/creating.html">Creating Notifications for Android Wear
-      </a></div>
-  </li>
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/wear/notifications/remote-input.html">Receiving Voice Input from a Notification
-      </a></div>
-  </li>
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/wear/notifications/pages.html">Adding Pages to a Notification
-      </a></div>
-  </li>
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/wear/notifications/stacks.html">Stacking Notifications
-      </a></div>
-  </li>
-
-  <li class="nav-section">
-    <div class="nav-section-header"><a href="/reference/android/preview/support/package-summary.html">Notification Reference</a></div>
-    <ul class="tree-list-children">
-<li class="nav-section">
-<div class="nav-section-header-ref"><span class="tree-list-subtitle package" title="android.preview.support.v4.app">android.preview.support.v4.app</span></div>
-  <ul>
-<li><a href="/reference/android/preview/support/v4/app/NotificationManagerCompat.html">NotificationManagerCompat</a></li>
-  </ul>
-</li>
-
-<li class="nav-section">
-<div class="nav-section-header-ref"><span class="tree-list-subtitle package" title="android.preview.support.wearable.notifications">android.preview.support.wearable.notifications</span></div>
-<ul>
-
-<li><a href="/reference/android/preview/support/wearable/notifications/RemoteInput.html">RemoteInput</a></li>
-<li><a href="/reference/android/preview/support/wearable/notifications/RemoteInput.Builder.html" >RemoteInput.Builder</a></li>
-
-<li><a href="/reference/android/preview/support/wearable/notifications/WearableNotifications.html">WearableNotifications</a></li>
-
-<li><a href="/reference/android/preview/support/wearable/notifications/WearableNotifications.Action.html">WearableNotifications.Action</a></li>
-
-<li><a href="/reference/android/preview/support/wearable/notifications/WearableNotifications.Action.Builder.html">WearableNotifications.Action.Builder</a></li>
-
-<li><a href="/reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html">WearableNotifications.Builder</a></li>
-	</ul>
-  </li>
-</ul>
-</li>
-
-
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/wear/license.html">License Agreement</a></div>
-  </li>
-
-
-</ul>
-
-        
-
-      </div>
-    </div> <!-- end side-nav -->
-    <script>
-      $(document).ready(function() {
-        scrollIntoView("devdoc-nav");
-        });
-    </script>
-
-
-
-
-<div class="col-12" id="doc-col" >
-
-
-  
-    
-      
-        <h1 itemprop="name" >UI Overview</h1>
-      
-    
-  
-
-
-  
-  <div id="jd-content">
-
-
-    <div class="jd-descr" itemprop="articleBody">
-    <style>
-h3 {
- padding:30px 0 10px;
-}
-</style>
-
-<p>A new form factor deserves a new UI model. At a high level, the Android Wear UI consists of two
-main spaces centered around the core functions of <strong>Suggest</strong> and
-<strong>Demand</strong>. Your application will have an important role to play in both of these
-spaces.</p>
-
-
-
-<h3 id="Stream">Suggest: The Context Stream</h3>
-
-<div class="wear-inset-video-container" style="float:right;margin:0 -22px 60px 40px">
-  <img class="wear-bezel-only" src="/wear/images/screens/bezel.png" alt="">
-  <img class="gif" src="/wear/images/screens/stream.gif">
-</div>
-
-<p>The context stream is a vertical list of cards, each showing a useful or timely piece of
-information. Much like Google Now on Android phones and tablets, users swipe vertically to navigate
-from card to card for a brief and comprehensive update about what's important to them. Only one card
-is displayed on screen at a time, and background images are used to provide additional visual
-information. Your application can create cards and inject them into the stream when they are most
-likely to be useful.</p>
-
-<p>Cards in the stream are more than simple notifications. They can be swiped horizontally to
-reveal additional pages. Further horizontal swiping may reveal tappable buttons, allowing the user
-to take action on the notification. Cards can also be dismissed by swiping left to right, removing
-them from the stream until the next time they have useful information to display.
-In the emulator, hovering the mouse over the top of the screen illuminates a blue bar at
-the top of the device that takes you home when clicked.</p>
-
-
-
-<h3 id="CueCard">Demand: The Cue Card</h3>
-
-<div class="wear-inset-video-container" style="float:right;margin:0 -22px 60px 40px">
-  <img class="wear-bezel-only" src="/wear/images/screens/bezel.png" alt="">
-  <img class="gif" src="/wear/images/screens/cuecard.gif">
-</div>
-
-<p>For cases where the context stream can't anticipate what the user would like to do, the cue card
-allows users to speak to their device. The cue card is opened by saying, "Ok Google" or by tapping
-on the "g" icon on the home screen. Swiping up on the cue card shows a list of actions, which can
-also be tapped.</p>
-
-<p>The list of actions includes Android intents for voice actions. The upcoming Android Wear SDK
-will enable developers to match their applications to these intents so users can perform actions
-using these voice commands. Multiple applications may register for a single voice intent, and users
-will have the opportunity to choose which application they prefer to use.</p>
-
-
-    </div>
-
-      <div class="content-footer layout-content-row"
-                    itemscope itemtype="http://schema.org/SiteNavigationElement">
-        <div class="layout-content-col col-9" style="padding-top:4px">
-          
-            <div class="g-plusone" data-size="medium"></div>
-          
-        </div>
-        
-        <div class="paging-links layout-content-col col-4">
-          
-        </div>
-        
-      </div>
-
-      
-      
-
-  </div> <!-- end jd-content -->
-
-<div id="footer" class="wrap" >
-        
-
-  <div id="copyright">
-    
-  Except as noted, this content is 
-  licensed under <a href="http://creativecommons.org/licenses/by/2.5/">
-  Creative Commons Attribution 2.5</a>. For details and 
-  restrictions, see the <a href="/license.html">Content 
-  License</a>.
-  </div>
-
-
-  <div id="footerlinks">
-    
-  <p>
-    <a href="/about/index.html">About Android</a>&nbsp;&nbsp;|&nbsp;
-    <a href="/legal.html">Legal</a>&nbsp;&nbsp;|&nbsp;
-    <a href="/support.html">Support</a>
-  </p>
-  </div>
-
-</div> <!-- end footer -->
-</div><!-- end doc-content -->
-
-</div> <!-- end body-content --> 
-
-
-
-
-
-
-<!-- Start of Tag -->
-<script type="text/javascript">
-var axel = Math.random() + "";
-var a = axel * 10000000000000;
-document.write('<iframe src="https://2507573.fls.doubleclick.net/activityi;src=2507573;type=other026;cat=googl348;ord=' + a + '?" width="1" height="1" frameborder="0" style="display:none"></iframe>');
-</script>
-<noscript>
-<iframe src="https://2507573.fls.doubleclick.net/activityi;src=2507573;type=other026;cat=googl348;ord=1?" width="1" height="1" frameborder="0" style="display:none"></iframe>
-</noscript>
-<!-- End of Tag -->
-</body>
-</html>
-
-
-
diff --git a/docs/html/wear/design/user-interface.jd b/docs/html/wear/design/user-interface.jd
new file mode 100644
index 0000000..2a3e9ef
--- /dev/null
+++ b/docs/html/wear/design/user-interface.jd
@@ -0,0 +1,58 @@
+page.title=UI Overview
+page.customHeadTag=<link rel="stylesheet" type="text/css" href="/wear/css/wear.css">
+
+@jd:body
+
+<style>
+h3 {
+ padding:30px 0 10px;
+}
+</style>
+
+<p>A new form factor deserves a new UI model. At a high level, the Android Wear UI consists of two
+main spaces centered around the core functions of <strong>Suggest</strong> and
+<strong>Demand</strong>. Your application will have an important role to play in both of these
+spaces.</p>
+
+
+
+<h3 id="Stream">Suggest: The Context Stream</h3>
+
+<div class="wear-inset-video-container" style="float:right;margin:0 -22px 60px 40px">
+  <img class="wear-bezel-only" src="{@docRoot}wear/images/screens/bezel.png" alt="">
+  <img class="gif" src="{@docRoot}wear/images/screens/stream.gif">
+</div>
+
+<p>The context stream is a vertical list of cards, each showing a useful or timely piece of
+information. Much like Google Now on Android phones and tablets, users swipe vertically to navigate
+from card to card for a brief and comprehensive update about what's important to them. Only one card
+is displayed on screen at a time, and background images are used to provide additional visual
+information. Your application can create cards and inject them into the stream when they are most
+likely to be useful.</p>
+
+<p>Cards in the stream are more than simple notifications. They can be swiped horizontally to
+reveal additional pages. Further horizontal swiping may reveal tappable buttons, allowing the user
+to take action on the notification. Cards can also be dismissed by swiping left to right, removing
+them from the stream until the next time they have useful information to display.
+In the emulator, hovering the mouse over the top of the screen illuminates a blue bar at
+the top of the device that takes you home when clicked.</p>
+
+
+
+<h3 id="CueCard">Demand: The Cue Card</h3>
+
+<div class="wear-inset-video-container" style="float:right;margin:0 -22px 60px 40px">
+  <img class="wear-bezel-only" src="{@docRoot}wear/images/screens/bezel.png" alt="">
+  <img class="gif" src="{@docRoot}wear/images/screens/cuecard.gif">
+</div>
+
+<p>For cases where the context stream can't anticipate what the user would like to do, the cue card
+allows users to speak to their device. The cue card is opened by saying, "Ok Google" or by tapping
+on the "g" icon on the home screen. Swiping up on the cue card shows a list of actions, which can
+also be tapped.</p>
+
+<p>The list of actions includes Android intents for voice actions. The upcoming Android Wear SDK
+will enable developers to match their applications to these intents so users can perform actions
+using these voice commands. Multiple applications may register for a single voice intent, and users
+will have the opportunity to choose which application they prefer to use.</p>
+
diff --git a/docs/html/wear/images/laptop-bridge.png b/docs/html/wear/images/laptop-bridge.png
index b481224..083b82b 100644
--- a/docs/html/wear/images/laptop-bridge.png
+++ b/docs/html/wear/images/laptop-bridge.png
Binary files differ
diff --git a/docs/html/wear/images/notif_summary_framed.png b/docs/html/wear/images/notif_summary_framed.png
new file mode 100644
index 0000000..17b1703
--- /dev/null
+++ b/docs/html/wear/images/notif_summary_framed.png
Binary files differ
diff --git a/docs/html/wear/index.html b/docs/html/wear/index.jd
similarity index 67%
rename from docs/html/wear/index.html
rename to docs/html/wear/index.jd
index 9660463..659e9f2 100644
--- a/docs/html/wear/index.html
+++ b/docs/html/wear/index.jd
@@ -1,286 +1,12 @@
-<!DOCTYPE html>
+page.title=Android Wear
+page.viewport_width=970
+fullpage=true
+no_footer_links=true
+page.customHeadTag=<link rel="stylesheet" type="text/css" href="/wear/css/wear.css">
 
+@jd:body
 
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-<html>
-<head>
-
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
-<meta name="viewport" content="width=970" />
-
-<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
-<title>Android Wear | Android Developers</title>
-
-<!-- STYLESHEETS -->
-<link rel="stylesheet"
-href="//fonts.googleapis.com/css?family=Roboto:light,regular,medium,thin,italic,mediumitalic,bold" title="roboto">
-<link href="/assets/css/default.css" rel="stylesheet" type="text/css">
-
-
-
-<!-- JAVASCRIPT -->
-<script src="//www.google.com/jsapi" type="text/javascript"></script>
-<script src="/assets/js/android_3p-bundle.js" type="text/javascript"></script>
-<link rel="stylesheet" type="text/css" href="/wear/css/wear.css">
-<script type="text/javascript">
-  var toRoot = "/";
-  var metaTags = [];
-  var devsite = false;
-</script>
-<script src="/assets/js/docs.js" type="text/javascript"></script>
-
-<script type="text/javascript">
-  var _gaq = _gaq || [];
-  _gaq.push(['_setAccount', 'UA-5831155-1']);
-  _gaq.push(['_trackPageview']);
-
-  (function() {
-    var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
-    ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
-    var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
-  })();
-</script>
-</head>
-
-<body class="gc-documentation 
-  " itemscope itemtype="http://schema.org/Article">
-
-
-  
-<a name="top"></a>
-
-    <!-- Header -->
-    <div id="header">
-        <div class="wrap" id="header-wrap">
-          <div class="col-3 logo-wear">
-          <a href="/wear/index.html">
-            <img src="/wear/images/android-wear.png" height="16" alt="Android Wear" />
-          </a>
-          </div>
-
-
-	<div class="col-8" style="margin:0"><h1 style="margin:1px 0 0 20px;padding:0;line-height:16px;
-  color:#666;font-weight:100;font-size:24px;">Developer Preview</h1></div>
-            
-
-          <!-- New Search -->
-          <div class="menu-container">
-            <div class="moremenu">
-	        <div id="more-btn"></div>
-	    </div>
-  <div class="morehover" id="moremenu">
-    <div class="top"></div>
-    <div class="mid">
-      <div class="header">Links</div>
-      <ul>
-        <li><a href="https://play.google.com/apps/publish/">Google Play Developer Console</a></li>
-        <li><a href="http://android-developers.blogspot.com/">Android Developers Blog</a></li>
-        <li><a href="/about/index.html">About Android</a></li>
-      </ul>
-      <div class="header">Android Sites</div>
-      <ul>
-        <li><a href="http://www.android.com">Android.com</a></li>
-        <li class="active"><a>Android Developers</a></li>
-        <li><a href="http://source.android.com">Android Open Source Project</a></li>
-      </ul>
-      
-      
-      
-        <div class="header">Language</div>
-          <div id="language" class="locales">
-            <select name="language" onChange="changeLangPref(this.value, true)">
-                <option value="en">English</option>
-                <option value="es">Español</option>
-                <option value="ja">日本語</option>
-                <option value="ko">한국어</option>
-                <option value="ru">Русский</option>
-                <option value="zh-cn">中文 (中国)</option>
-                <option value="zh-tw">中文 (台灣)</option>
-            </select>
-          </div>
-        <script type="text/javascript">
-          <!--
-          loadLangPref();
-            //-->
-        </script>
-      
-      
-
-
-      <br class="clearfix" />
-    </div><!-- end mid -->
-    <div class="bottom"></div>
-  </div><!-- end morehover -->
-
-  <div class="search" id="search-container">
-    <div class="search-inner">
-      <div id="search-btn"></div>
-      <div class="left"></div>
-      <form onsubmit="return submit_search()">
-        <input id="search_autocomplete" type="text" value="" autocomplete="off" name="q"
-onfocus="search_focus_changed(this, true)" onblur="search_focus_changed(this, false)"
-onkeydown="return search_changed(event, true, '/')" 
-onkeyup="return search_changed(event, false, '/')" />
-      </form>
-      <div class="right"></div>
-        <a class="close hide">close</a>
-        <div class="left"></div>
-        <div class="right"></div>
-    </div>
-  </div><!--  end search -->
-
-  <div class="search_filtered_wrapper reference">
-    <div class="suggest-card reference no-display">
-      <ul class="search_filtered">
-      </ul>
-    </div>
-  </div>
-
-  <div class="search_filtered_wrapper docs">
-    <div class="suggest-card dummy no-display">&nbsp;</div>
-    <div class="suggest-card develop no-display">
-      <ul class="search_filtered">
-      </ul>
-      <div class="child-card guides no-display">
-      </div>
-      <div class="child-card training no-display">
-      </div>
-      <div class="child-card samples no-display">
-      </div>
-    </div>
-    <div class="suggest-card design no-display">
-      <ul class="search_filtered">
-      </ul>
-    </div>
-    <div class="suggest-card distribute no-display">
-      <ul class="search_filtered">
-      </ul>
-    </div>
-  </div><!-- end search_filtered_wrapper -->
-
-  </div>
-  <!-- end menu_container -->
-
-
-        </div><!-- end header-wrap -->
-    </div>
-    <!-- /Header -->
-
-
-  <div id="searchResults" class="wrap" style="display:none;">
-          <h2 id="searchTitle">Results</h2>
-          <div id="leftSearchControl" class="search-control">Loading...</div>
-  </div>
-
-  
-
-  
-
-  <div id="body-content">
-
-
-
-
-<div class="fullpage" >
-
-
-  
-
-
-  
-  <div id="jd-content">
-
-
-    <div class="jd-descr" itemprop="articleBody">
-    <style>
+<style>
 .fullpage>#footer,
 #jd-content>.content-footer.wrap {
   display:none;
@@ -395,13 +121,13 @@
                 </p>
               </div>
               <div class="col-3-wide">
-                <img src="/wear/images/screens/circle_message2.png" alt="Image of a Hangouts message">
+                <img src="/wear/images/screens/circle_message2.png" itemprop="image" alt="" >
                 <p class="wear-small">
                   Get glanceable, actionable information at just the right time throughout the day.
                 </p>
               </div>
               <div class="col-3-wide">
-                <img src="/wear/images/screens/fitness-24.png" alt="Image showing ">
+                <img src="/wear/images/screens/fitness-24.png" alt="">
                 <p class="wear-small">
                   A wide range of sensors is available to your applications, from accelerometers to heart rate monitors.
                 </p>
@@ -471,10 +197,10 @@
             </div>
 
             <p>
-              You can also trigger your notifications contextually using existing Android APIs.  For example, use <a href="/training/location/geofencing.html">geofences</a> to provide glanceable information to your users when they are at home, or use the <a href="/training/location/activity-recognition.html">activity detection APIs</a> to send messages to your users’ wrists while they are bicycling.
+              You can also trigger your notifications contextually using existing Android APIs.  For example, use <a href="{@docRoot}training/location/geofencing.html">geofences</a> to provide glanceable information to your users when they are at home, or use the <a href="{@docRoot}training/location/activity-recognition.html">activity detection APIs</a> to send messages to your users’ wrists while they are bicycling.
             </p>
 
-            <p>See the <a href="/wear/design/index.html">Android Wear Developer Preview Design Principles</a> for more suggestions on creating great wearable experiences.</p>
+            <p>See the <a href="{@docRoot}wear/design/index.html">Android Wear Developer Preview Design Principles</a> for more suggestions on creating great wearable experiences.</p>
 
           </div>
         </div>  <!-- end .wrap -->
@@ -677,63 +403,3 @@
   });
   </script>
 
-
-    </div>
-
-      <div class="content-footer wrap"
-                    itemscope itemtype="http://schema.org/SiteNavigationElement">
-        <div class="layout-content-col col-16" style="padding-top:4px">
-          <style>#___plusone_0 {float:right !important;}</style>
-            <div class="g-plusone" data-size="medium"></div>
-          
-        </div>
-        
-        <div class="paging-links layout-content-col col-4">
-          
-        </div>
-        
-      </div>
-
-      
-      
-
-  </div> <!-- end jd-content -->
-
-<div id="footer" class="wrap" style="width:940px">
-        
-
-  <div id="copyright">
-    
-  Except as noted, this content is 
-  licensed under <a href="http://creativecommons.org/licenses/by/2.5/">
-  Creative Commons Attribution 2.5</a>. For details and 
-  restrictions, see the <a href="/license.html">Content 
-  License</a>.
-  </div>
-
-
-</div> <!-- end footer -->
-</div><!-- end doc-content -->
-
-</div> <!-- end body-content --> 
-
-
-
-
-
-
-<!-- Start of Tag -->
-<script type="text/javascript">
-var axel = Math.random() + "";
-var a = axel * 10000000000000;
-document.write('<iframe src="https://2507573.fls.doubleclick.net/activityi;src=2507573;type=other026;cat=googl348;ord=' + a + '?" width="1" height="1" frameborder="0" style="display:none"></iframe>');
-</script>
-<noscript>
-<iframe src="https://2507573.fls.doubleclick.net/activityi;src=2507573;type=other026;cat=googl348;ord=1?" width="1" height="1" frameborder="0" style="display:none"></iframe>
-</noscript>
-<!-- End of Tag -->
-</body>
-</html>
-
-
-
diff --git a/docs/html/wear/license.html b/docs/html/wear/license.jd
similarity index 63%
rename from docs/html/wear/license.html
rename to docs/html/wear/license.jd
index c7569bc..b07dacf 100644
--- a/docs/html/wear/license.html
+++ b/docs/html/wear/license.jd
@@ -1,379 +1,9 @@
-<!DOCTYPE html>
+page.title=Developer Preview License Agreement
 
+@jd:body
 
 
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-<html>
-<head>
-
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
-<meta name="viewport" content="width=device-width" />
-
-<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
-<title>Developer Preview License Agreement | Android Developers</title>
-
-<!-- STYLESHEETS -->
-<link rel="stylesheet"
-href="//fonts.googleapis.com/css?family=Roboto:light,regular,medium,thin,italic,mediumitalic,bold" title="roboto">
-<link href="/assets/css/default.css" rel="stylesheet" type="text/css">
-
-
-
-<!-- JAVASCRIPT -->
-<script src="//www.google.com/jsapi" type="text/javascript"></script>
-<script src="/assets/js/android_3p-bundle.js" type="text/javascript"></script>
-<script type="text/javascript">
-  var toRoot = "/";
-  var metaTags = [];
-  var devsite = false;
-</script>
-<script src="/assets/js/docs.js" type="text/javascript"></script>
-
-<script type="text/javascript">
-  var _gaq = _gaq || [];
-  _gaq.push(['_setAccount', 'UA-5831155-1']);
-  _gaq.push(['_trackPageview']);
-
-  (function() {
-    var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
-    ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
-    var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
-  })();
-</script>
-</head>
-
-<body class="gc-documentation 
-  " itemscope itemtype="http://schema.org/Article">
-
-
-  
-<a name="top"></a>
-
-    <!-- Header -->
-    <div id="header">
-        <div class="wrap" id="header-wrap">
-          <div class="col-3 logo-wear">
-          <a href="/wear/index.html">
-            <img src="/wear/images/android-wear.png" height="16" alt="Android Wear" />
-          </a>
-          </div>
-
-
-	<div class="col-8" style="margin:0"><h1 style="margin:1px 0 0 20px;padding:0;line-height:16px;
-  color:#666;font-weight:100;font-size:24px;">Developer Preview</h1></div>
-            
-
-          <!-- New Search -->
-          <div class="menu-container">
-            <div class="moremenu">
-	        <div id="more-btn"></div>
-	    </div>
-  <div class="morehover" id="moremenu">
-    <div class="top"></div>
-    <div class="mid">
-      <div class="header">Links</div>
-      <ul>
-        <li><a href="https://play.google.com/apps/publish/">Google Play Developer Console</a></li>
-        <li><a href="http://android-developers.blogspot.com/">Android Developers Blog</a></li>
-        <li><a href="/about/index.html">About Android</a></li>
-      </ul>
-      <div class="header">Android Sites</div>
-      <ul>
-        <li><a href="http://www.android.com">Android.com</a></li>
-        <li class="active"><a>Android Developers</a></li>
-        <li><a href="http://source.android.com">Android Open Source Project</a></li>
-      </ul>
-      
-      
-      
-        <div class="header">Language</div>
-          <div id="language" class="locales">
-            <select name="language" onChange="changeLangPref(this.value, true)">
-                <option value="en">English</option>
-                <option value="es">Español</option>
-                <option value="ja">日本語</option>
-                <option value="ko">한국어</option>
-                <option value="ru">Русский</option>
-                <option value="zh-cn">中文 (中国)</option>
-                <option value="zh-tw">中文 (台灣)</option>
-            </select>
-          </div>
-        <script type="text/javascript">
-          <!--
-          loadLangPref();
-            //-->
-        </script>
-      
-      
-
-
-      <br class="clearfix" />
-    </div><!-- end mid -->
-    <div class="bottom"></div>
-  </div><!-- end morehover -->
-
-  <div class="search" id="search-container">
-    <div class="search-inner">
-      <div id="search-btn"></div>
-      <div class="left"></div>
-      <form onsubmit="return submit_search()">
-        <input id="search_autocomplete" type="text" value="" autocomplete="off" name="q"
-onfocus="search_focus_changed(this, true)" onblur="search_focus_changed(this, false)"
-onkeydown="return search_changed(event, true, '/')" 
-onkeyup="return search_changed(event, false, '/')" />
-      </form>
-      <div class="right"></div>
-        <a class="close hide">close</a>
-        <div class="left"></div>
-        <div class="right"></div>
-    </div>
-  </div><!--  end search -->
-
-  <div class="search_filtered_wrapper reference">
-    <div class="suggest-card reference no-display">
-      <ul class="search_filtered">
-      </ul>
-    </div>
-  </div>
-
-  <div class="search_filtered_wrapper docs">
-    <div class="suggest-card dummy no-display">&nbsp;</div>
-    <div class="suggest-card develop no-display">
-      <ul class="search_filtered">
-      </ul>
-      <div class="child-card guides no-display">
-      </div>
-      <div class="child-card training no-display">
-      </div>
-      <div class="child-card samples no-display">
-      </div>
-    </div>
-    <div class="suggest-card design no-display">
-      <ul class="search_filtered">
-      </ul>
-    </div>
-    <div class="suggest-card distribute no-display">
-      <ul class="search_filtered">
-      </ul>
-    </div>
-  </div><!-- end search_filtered_wrapper -->
-
-  </div>
-  <!-- end menu_container -->
-
-
-        </div><!-- end header-wrap -->
-    </div>
-    <!-- /Header -->
-
-
-  <div id="searchResults" class="wrap" style="display:none;">
-          <h2 id="searchTitle">Results</h2>
-          <div id="leftSearchControl" class="search-control">Loading...</div>
-  </div>
-
-  
-
-  
-
-  <div class="wrap clearfix" id="body-content">
-    <div class="col-4" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
-      <div id="devdoc-nav" class="scroll-pane">
-<a class="totop" href="#top" data-g-event="left-nav-top">to top</a>
-
-<ul id="nav">
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/wear/preview/start.html">Get Started
-      </a></div>
-  </li>
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/wear/design/user-interface.html">UI Overview
-      </a></div>
-  </li>
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/wear/design/index.html">Design Principles
-      </a></div>
-  </li>
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/wear/notifications/creating.html">Creating Notifications for Android Wear
-      </a></div>
-  </li>
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/wear/notifications/remote-input.html">Receiving Voice Input from a Notification
-      </a></div>
-  </li>
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/wear/notifications/pages.html">Adding Pages to a Notification
-      </a></div>
-  </li>
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/wear/notifications/stacks.html">Stacking Notifications
-      </a></div>
-  </li>
-
-  <li class="nav-section">
-    <div class="nav-section-header"><a href="/reference/android/preview/support/package-summary.html">Notification Reference</a></div>
-    <ul class="tree-list-children">
-<li class="nav-section">
-<div class="nav-section-header-ref"><span class="tree-list-subtitle package" title="android.preview.support.v4.app">android.preview.support.v4.app</span></div>
-  <ul>
-<li><a href="/reference/android/preview/support/v4/app/NotificationManagerCompat.html">NotificationManagerCompat</a></li>
-  </ul>
-</li>
-
-<li class="nav-section">
-<div class="nav-section-header-ref"><span class="tree-list-subtitle package" title="android.preview.support.wearable.notifications">android.preview.support.wearable.notifications</span></div>
-<ul>
-
-<li><a href="/reference/android/preview/support/wearable/notifications/RemoteInput.html">RemoteInput</a></li>
-<li><a href="/reference/android/preview/support/wearable/notifications/RemoteInput.Builder.html" >RemoteInput.Builder</a></li>
-
-<li><a href="/reference/android/preview/support/wearable/notifications/WearableNotifications.html">WearableNotifications</a></li>
-
-<li><a href="/reference/android/preview/support/wearable/notifications/WearableNotifications.Action.html">WearableNotifications.Action</a></li>
-
-<li><a href="/reference/android/preview/support/wearable/notifications/WearableNotifications.Action.Builder.html">WearableNotifications.Action.Builder</a></li>
-
-<li><a href="/reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html">WearableNotifications.Builder</a></li>
-	</ul>
-  </li>
-</ul>
-</li>
-
-
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/wear/license.html">License Agreement</a></div>
-  </li>
-
-
-</ul>
-
-        
-
-      </div>
-    </div> <!-- end side-nav -->
-    <script>
-      $(document).ready(function() {
-        scrollIntoView("devdoc-nav");
-        });
-    </script>
-
-
-
-
-<div class="col-12" id="doc-col" >
-
-
-  
-    
-      
-        <h1 itemprop="name" >Developer Preview License Agreement</h1>
-      
-    
-  
-
-
-  
-  <div id="jd-content">
-
-
-    <div class="jd-descr" itemprop="articleBody">
-    <div class="sdk-terms" style="height:auto;border:0;padding:0;width:700px">
+<div class="sdk-terms" style="height:auto;border:0;padding:0;width:700px">
 This is the Android Wear Developer Preview License Agreement.
 
 1. Introduction
@@ -510,72 +140,3 @@
 
 14.7 This License Agreement, and your relationship with Google under this License Agreement, shall be governed by the laws of the State of California without regard to its conflict of laws provisions. You and Google agree to submit to the exclusive jurisdiction of the courts located within the county of Santa Clara, California to resolve any legal matter arising from this License Agreement. Notwithstanding this, you agree that Google shall still be allowed to apply for injunctive remedies (or an equivalent type of urgent legal relief) in any jurisdiction.
 </div>
-
-    </div>
-
-      <div class="content-footer layout-content-row"
-                    itemscope itemtype="http://schema.org/SiteNavigationElement">
-        <div class="layout-content-col col-9" style="padding-top:4px">
-          
-            <div class="g-plusone" data-size="medium"></div>
-          
-        </div>
-        
-        <div class="paging-links layout-content-col col-4">
-          
-        </div>
-        
-      </div>
-
-      
-      
-
-  </div> <!-- end jd-content -->
-
-<div id="footer" class="wrap" >
-        
-
-  <div id="copyright">
-    
-  Except as noted, this content is 
-  licensed under <a href="http://creativecommons.org/licenses/by/2.5/">
-  Creative Commons Attribution 2.5</a>. For details and 
-  restrictions, see the <a href="/license.html">Content 
-  License</a>.
-  </div>
-
-
-  <div id="footerlinks">
-    
-  <p>
-    <a href="/about/index.html">About Android</a>&nbsp;&nbsp;|&nbsp;
-    <a href="/legal.html">Legal</a>&nbsp;&nbsp;|&nbsp;
-    <a href="/support.html">Support</a>
-  </p>
-  </div>
-
-</div> <!-- end footer -->
-</div><!-- end doc-content -->
-
-</div> <!-- end body-content --> 
-
-
-
-
-
-
-<!-- Start of Tag -->
-<script type="text/javascript">
-var axel = Math.random() + "";
-var a = axel * 10000000000000;
-document.write('<iframe src="https://2507573.fls.doubleclick.net/activityi;src=2507573;type=other026;cat=googl348;ord=' + a + '?" width="1" height="1" frameborder="0" style="display:none"></iframe>');
-</script>
-<noscript>
-<iframe src="https://2507573.fls.doubleclick.net/activityi;src=2507573;type=other026;cat=googl348;ord=1?" width="1" height="1" frameborder="0" style="display:none"></iframe>
-</noscript>
-<!-- End of Tag -->
-</body>
-</html>
-
-
-
diff --git a/docs/html/wear/notifications/creating.html b/docs/html/wear/notifications/creating.html
deleted file mode 100644
index 5022c75..0000000
--- a/docs/html/wear/notifications/creating.html
+++ /dev/null
@@ -1,722 +0,0 @@
-<!DOCTYPE html>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-<html>
-<head>
-
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
-<meta name="viewport" content="width=device-width" />
-
-<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
-<title>Creating Notifications for Android Wear | Android Developers</title>
-
-<!-- STYLESHEETS -->
-<link rel="stylesheet"
-href="//fonts.googleapis.com/css?family=Roboto:light,regular,medium,thin,italic,mediumitalic,bold" title="roboto">
-<link href="/assets/css/default.css" rel="stylesheet" type="text/css">
-
-
-
-<!-- JAVASCRIPT -->
-<script src="//www.google.com/jsapi" type="text/javascript"></script>
-<script src="/assets/js/android_3p-bundle.js" type="text/javascript"></script>
-<script type="text/javascript">
-  var toRoot = "/";
-  var metaTags = [];
-  var devsite = false;
-</script>
-<script src="/assets/js/docs.js" type="text/javascript"></script>
-
-<script type="text/javascript">
-  var _gaq = _gaq || [];
-  _gaq.push(['_setAccount', 'UA-5831155-1']);
-  _gaq.push(['_trackPageview']);
-
-  (function() {
-    var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
-    ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
-    var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
-  })();
-</script>
-</head>
-
-<body class="gc-documentation 
-  " itemscope itemtype="http://schema.org/Article">
-
-
-  
-<a name="top"></a>
-
-    <!-- Header -->
-    <div id="header">
-        <div class="wrap" id="header-wrap">
-          <div class="col-3 logo-wear">
-          <a href="/wear/index.html">
-            <img src="/wear/images/android-wear.png" height="16" alt="Android Wear" />
-          </a>
-          </div>
-
-
-	<div class="col-8" style="margin:0"><h1 style="margin:1px 0 0 20px;padding:0;line-height:16px;
-  color:#666;font-weight:100;font-size:24px;">Developer Preview</h1></div>
-            
-
-          <!-- New Search -->
-          <div class="menu-container">
-            <div class="moremenu">
-	        <div id="more-btn"></div>
-	    </div>
-  <div class="morehover" id="moremenu">
-    <div class="top"></div>
-    <div class="mid">
-      <div class="header">Links</div>
-      <ul>
-        <li><a href="https://play.google.com/apps/publish/">Google Play Developer Console</a></li>
-        <li><a href="http://android-developers.blogspot.com/">Android Developers Blog</a></li>
-        <li><a href="/about/index.html">About Android</a></li>
-      </ul>
-      <div class="header">Android Sites</div>
-      <ul>
-        <li><a href="http://www.android.com">Android.com</a></li>
-        <li class="active"><a>Android Developers</a></li>
-        <li><a href="http://source.android.com">Android Open Source Project</a></li>
-      </ul>
-      
-      
-      
-        <div class="header">Language</div>
-          <div id="language" class="locales">
-            <select name="language" onChange="changeLangPref(this.value, true)">
-                <option value="en">English</option>
-                <option value="es">Español</option>
-                <option value="ja">日本語</option>
-                <option value="ko">한국어</option>
-                <option value="ru">Русский</option>
-                <option value="zh-cn">中文 (中国)</option>
-                <option value="zh-tw">中文 (台灣)</option>
-            </select>
-          </div>
-        <script type="text/javascript">
-          <!--
-          loadLangPref();
-            //-->
-        </script>
-      
-      
-
-
-      <br class="clearfix" />
-    </div><!-- end mid -->
-    <div class="bottom"></div>
-  </div><!-- end morehover -->
-
-  <div class="search" id="search-container">
-    <div class="search-inner">
-      <div id="search-btn"></div>
-      <div class="left"></div>
-      <form onsubmit="return submit_search()">
-        <input id="search_autocomplete" type="text" value="" autocomplete="off" name="q"
-onfocus="search_focus_changed(this, true)" onblur="search_focus_changed(this, false)"
-onkeydown="return search_changed(event, true, '/')" 
-onkeyup="return search_changed(event, false, '/')" />
-      </form>
-      <div class="right"></div>
-        <a class="close hide">close</a>
-        <div class="left"></div>
-        <div class="right"></div>
-    </div>
-  </div><!--  end search -->
-
-  <div class="search_filtered_wrapper reference">
-    <div class="suggest-card reference no-display">
-      <ul class="search_filtered">
-      </ul>
-    </div>
-  </div>
-
-  <div class="search_filtered_wrapper docs">
-    <div class="suggest-card dummy no-display">&nbsp;</div>
-    <div class="suggest-card develop no-display">
-      <ul class="search_filtered">
-      </ul>
-      <div class="child-card guides no-display">
-      </div>
-      <div class="child-card training no-display">
-      </div>
-      <div class="child-card samples no-display">
-      </div>
-    </div>
-    <div class="suggest-card design no-display">
-      <ul class="search_filtered">
-      </ul>
-    </div>
-    <div class="suggest-card distribute no-display">
-      <ul class="search_filtered">
-      </ul>
-    </div>
-  </div><!-- end search_filtered_wrapper -->
-
-  </div>
-  <!-- end menu_container -->
-
-
-        </div><!-- end header-wrap -->
-    </div>
-    <!-- /Header -->
-
-
-  <div id="searchResults" class="wrap" style="display:none;">
-          <h2 id="searchTitle">Results</h2>
-          <div id="leftSearchControl" class="search-control">Loading...</div>
-  </div>
-
-  
-
-  
-
-  <div class="wrap clearfix" id="body-content">
-    <div class="col-4" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
-      <div id="devdoc-nav" class="scroll-pane">
-<a class="totop" href="#top" data-g-event="left-nav-top">to top</a>
-
-<ul id="nav">
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/wear/preview/start.html">Get Started
-      </a></div>
-  </li>
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/wear/design/user-interface.html">UI Overview
-      </a></div>
-  </li>
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/wear/design/index.html">Design Principles
-      </a></div>
-  </li>
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/wear/notifications/creating.html">Creating Notifications for Android Wear
-      </a></div>
-  </li>
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/wear/notifications/remote-input.html">Receiving Voice Input from a Notification
-      </a></div>
-  </li>
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/wear/notifications/pages.html">Adding Pages to a Notification
-      </a></div>
-  </li>
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/wear/notifications/stacks.html">Stacking Notifications
-      </a></div>
-  </li>
-
-  <li class="nav-section">
-    <div class="nav-section-header"><a href="/reference/android/preview/support/package-summary.html">Notification Reference</a></div>
-    <ul class="tree-list-children">
-<li class="nav-section">
-<div class="nav-section-header-ref"><span class="tree-list-subtitle package" title="android.preview.support.v4.app">android.preview.support.v4.app</span></div>
-  <ul>
-<li><a href="/reference/android/preview/support/v4/app/NotificationManagerCompat.html">NotificationManagerCompat</a></li>
-  </ul>
-</li>
-
-<li class="nav-section">
-<div class="nav-section-header-ref"><span class="tree-list-subtitle package" title="android.preview.support.wearable.notifications">android.preview.support.wearable.notifications</span></div>
-<ul>
-
-<li><a href="/reference/android/preview/support/wearable/notifications/RemoteInput.html">RemoteInput</a></li>
-<li><a href="/reference/android/preview/support/wearable/notifications/RemoteInput.Builder.html" >RemoteInput.Builder</a></li>
-
-<li><a href="/reference/android/preview/support/wearable/notifications/WearableNotifications.html">WearableNotifications</a></li>
-
-<li><a href="/reference/android/preview/support/wearable/notifications/WearableNotifications.Action.html">WearableNotifications.Action</a></li>
-
-<li><a href="/reference/android/preview/support/wearable/notifications/WearableNotifications.Action.Builder.html">WearableNotifications.Action.Builder</a></li>
-
-<li><a href="/reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html">WearableNotifications.Builder</a></li>
-	</ul>
-  </li>
-</ul>
-</li>
-
-
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/wear/license.html">License Agreement</a></div>
-  </li>
-
-
-</ul>
-
-        
-
-      </div>
-    </div> <!-- end side-nav -->
-    <script>
-      $(document).ready(function() {
-        scrollIntoView("devdoc-nav");
-        });
-    </script>
-
-
-
-
-<div class="col-12" id="doc-col" >
-
-
-  
-    
-      
-        <h1 itemprop="name" >Creating Notifications for Android Wear</h1>
-      
-    
-  
-
-
-  
-  <div id="jd-content">
-
-
-    <div class="jd-descr" itemprop="articleBody">
-    <p>When an Android device such as a phone or tablet is connected to an Android wearable,
-all notifications are shared between the devices by default. On the Android wearable, each
-notification appears as a new card in the <a href="/wear/design/user-interface.html#Stream"
->context stream</a>.</p>
-
-<img src="/wear/images/notification_phone@2x.png" width="700" height="265" />
-
-
-<p>So without any effort, your app notifications are available to users on Android Wear.
-However, you can enhance the user experience in several ways. For instance,
-if users may respond to a notification by entering text, such as to reply to
-a message, you can add the ability for users to reply by voice directly from the
-wearable.</p>
-
-<p>To help you provide the best user experience
-for your notifications on Android Wear, this guide shows you how to
-build notifications using standard templates in
-the <code><a href="/reference/android/support/v4/app/NotificationCompat.Builder.html">NotificationCompat.Builder</a></code> APIs, plus how to begin
-extending your notification's capabilities for the wearable user experience.</p>
-
-<p class="note"><strong>Note:</strong>
-Notifications using <code><a href="/reference/android/widget/RemoteViews.html">RemoteViews</a></code> are stripped of custom
-layouts and the system uses only the text and icons in the
-<code><a href="/reference/android/app/Notification.html">Notification</a></code> object to
-display the notification in a card. However, custom card layouts will be supported by
-the official Android Wear SDK that is coming later.</p>
-</div>
-
-
-
-
-<h2 id="Import">Import the Necessary Classes</h2>
-
-<p>To begin development, you must first complete the instructions in the <a
-href="/wear/preview/start">Get Started with the Developer Preview</a> document.
-As mentioned in that document, your app must include
-both the <a href="http://developer.android.com/tools/support-library/features.html#v4">v4 support
-library</a> and the Developer Preview support library. So to get started,
-you should include the following imports in your project code:</p>
-
-<pre>
-import android.preview.support.wearable.notifications.*;
-import android.preview.support.v4.app.NotificationManagerCompat;
-import android.support.v4.app.NotificationCompat;
-</pre>
-
-<p class="caution"><strong>Caution:</strong>
-The APIs in the current Android Wear Developer Preview are intended for <b>development and testing purposes only</b>, not for production apps. Google may change this Developer Preview significantly prior to the official release of the Android Wear SDK. You may not publicly distribute or ship any application using this Developer Preview, as this Developer Preview will no longer be supported after the official SDK is released (which will cause applications based only on the Developer Preview to break).</p>
-
-
-
-<h2 id="NotificationBuilder">Create Notifications with the Notification Builder</h2>
-
-<p>The <a href="http://developer.android.com/tools/support-library/features.html#v4">v4
-support library</a> allows you to create notifications using the latest notification features
-such as action buttons and large icons, while remaining compatible with Android 1.6 (API level
-4) and higher.</p>
-
-
-<p>For example, here's some code that creates and issues a notification using the
-<code><a href="/reference/android/support/v4/app/NotificationCompat.html">NotificationCompat</a></code> APIs combined with the new
-<a href="/reference/android/preview/support/v4/app/NotificationManagerCompat.html">
-<code>NotificationManagerCompat</code></a> API:</p>
-
-
-<pre>
-int notificationId = 001;
-// Build intent for notification content
-Intent viewIntent = new Intent(this, ViewEventActivity.class);
-viewIntent.putExtra(EXTRA_EVENT_ID, eventId);
-PendingIntent viewPendingIntent =
-        PendingIntent.getActivity(this, 0, viewIntent, 0);
-
-NotificationCompat.Builder notificationBuilder =
-        new NotificationCompat.Builder(this)
-        .setSmallIcon(R.drawable.ic_event)
-        .setContentTitle(eventTitle)
-        .setContentText(eventLocation)
-        .setContentIntent(viewPendingIntent);
-
-// Get an instance of the NotificationManager service
-NotificationManagerCompat notificationManager =
-        NotificationManagerCompat.from(this);
-
-// Build the notification and issues it with notification manager.
-notificationManager.notify(notificationId, notificationBuilder.build());
-</pre>
-
-<p>When this notification appears on a handheld device, the user can invoke the
-<code><a href="/reference/android/app/PendingIntent.html">PendingIntent</a></code>
-specified by the <code><a href="/reference/android/support/v4/app/NotificationCompat.Builder.html#setContentIntent(android.app.PendingIntent)">setContentIntent()</a></code> method by touching the notification. When this
-notification appears on an Android wearable, the user can swipe the notification to the left to
-reveal the <strong>Open</strong> action, which invokes the intent on the handheld device.</p>
-
-
-
-
-
-
-<img src="/wear/images/circle_email_action.png" height="200" style="float:right;clear:right;margin:0 0 20px 60px" />
-
-<h2 id="ActionButtons">Add Action Buttons</h2>
-
-<p>In addition to the primary content action defined by
-<code><a href="/reference/android/support/v4/app/NotificationCompat.Builder.html#setContentIntent(android.app.PendingIntent)">setContentIntent()</a></code>, you can add other actions by passing a <code><a href="/reference/android/app/PendingIntent.html">PendingIntent</a></code> to
-the <code><a href="/reference/android/support/v4/app/NotificationCompat.Builder.html#addAction(int, java.lang.CharSequence, android.app.PendingIntent)">addAction()</a></code> method.</p>
-
-<p>For example, the following code shows the same type of notification from above, but adds an
-action to view the event location on a map.</p>
-
-<pre style="clear:right">
-// Build an intent for an action to view a map
-Intent mapIntent = new Intent(Intent.ACTION_VIEW);
-Uri geoUri = Uri.parse("geo:0,0?q=" + Uri.encode(location));
-mapIntent.setData(geoUri);
-PendingIntent mapPendingIntent =
-        PendingIntent.getActivity(this, 0, mapIntent, 0);
-
-NotificationCompat.Builder notificationBuilder =
-        new NotificationCompat.Builder(this)
-        .setSmallIcon(R.drawable.ic_event)
-        .setContentTitle(eventTitle)
-        .setContentText(eventLocation)
-        .setContentIntent(viewPendingIntent)
-        <b>.addAction(R.drawable.ic_map,
-                getString(R.string.map), mapPendingIntent);</b>
-</pre>
-
-<p>On a handheld device, the action appears as an
-additional button attached to the notification. On an Android wearable, the action appears as
-a large button when the user swipes the notification to the left. When the user taps the action,
-the associated <code><a href="/reference/android/content/Intent.html">Intent</a></code> is invoked on the handheld device.</p>
-
-<p class="note"><strong>Tip:</strong> If your notifications includes a "Reply" action
-  (such as for a messaging app), you can enhance the behavior by enabling
-  voice input replies directly from the Android wearable. For more information, read
-  <a href="/wear/notifications/remote-input.html">Receiving Voice Input from a Notification</a>.
-</p>
-
-<p>For details about designing action buttons (including the icon specifications), see the
-<a href="/wear/design/index.html#NotifictionActions">Design Principles of Android
-Wear</a>.</p>
-
-
-<h2 id="BigView">Add a Big View</h2>
-
-<img src="/wear/images/06_images.png" height="200" style="float:right;margin:0 0 20px 40px" />
-
-<p>You can insert extended text content
-to your notification by adding one of the "big view" styles to your notification. On a
-handheld device, users can see the big view content by expanding the notification,
-while on Android Wear, the big view content is visible by default.</p>
-
-<p>To add the extended content to your notification, call <code><a href="/reference/android/support/v4/app/NotificationCompat.Builder.html#setStyle(android.support.v4.app.NotificationCompat.Style)">setStyle()</a></code> on the <code><a href="/reference/android/support/v4/app/NotificationCompat.Builder.html">NotificationCompat.Builder</a></code> object, passing it an instance of either
-<code><a href="/reference/android/support/v4/app/NotificationCompat.BigTextStyle.html">BigTextStyle</a></code> or
-<code><a href="/reference/android/support/v4/app/NotificationCompat.InboxStyle.html">InboxStyle</a></code>.</p>
-
-<p>For example, the following code adds an instance of
-<code><a href="/reference/android/support/v4/app/NotificationCompat.BigTextStyle.html">NotificationCompat.BigTextStyle</a></code> to the event notification,
-in order to include the complete event description (which includes more text than can fit
-into the space provided for <code><a href="/reference/android/support/v4/app/NotificationCompat.Builder.html#setContentText(java.lang.CharSequence)">setContentText()</a></code>).</p>
-
-
-<pre style="clear:right">
-// Specify the 'big view' content to display the long
-// event description that may not fit the normal content text.
-BigTextStyle bigStyle = new NotificationCompat.BigTextStyle();
-bigStyle.bigText(eventDescription);
-
-NotificationCompat.Builder notificationBuilder =
-        new NotificationCompat.Builder(this)
-        .setSmallIcon(R.drawable.ic_event)
-        .setLargeIcon(BitmapFractory.decodeResource(
-                getResources(), R.drawable.notif_background))
-        .setContentTitle(eventTitle)
-        .setContentText(eventLocation)
-        .setContentIntent(viewPendingIntent)
-        .addAction(R.drawable.ic_map,
-                getString(R.string.map), mapPendingIntent)
-        <b>.setStyle(bigStyle);</b>
-</pre>
-
-<p>Notice that you can add a large background image to any notification using the
-<code><a href="/reference/android/support/v4/app/NotificationCompat.Builder.html#setLargeIcon(android.graphics.Bitmap)">setLargeIcon()</a></code>
-method. For more information about designing notifications with large images, see the
-<a href="/wear/design/index.html#Images">Design Principles of Android
-Wear</a>.</p>
-
-
-
-<h2 id="NewFeatures">Add New Features for Wearables</h2>
-
-<p>The Android Wear preview support library provides new APIs that
-  allow you to enhance the user experience for notifications on a wearable device. For example,
-  you can add additional pages of content that users can view by swiping to the left, or add the ability
-for users to deliver your app a text response using voice input.</p>
-
-<p>To use these new APIs, pass your instance of
-<code><a href="/reference/android/support/v4/app/NotificationCompat.Builder.html">NotificationCompat.Builder</a></code> to the
-  <a href="/reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html#WearableNotifications.Builder(android.content.Context)"> <code>WearableNotifications.Builder()</code></a> constructor. You can then add new
-features to your notification using the
-  <a href="/reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html"
-  ><code>WearableNotifications.Builder</code></a> methods. For example:</p>
-
-<pre>
-// Create a NotificationCompat.Builder for standard notification features
-NotificationCompat.Builder notificationBuilder =
-        new NotificationCompat.Builder(mContext)
-        .setContentTitle("New mail from " + sender.toString())
-        .setContentText(subject)
-        .setSmallIcon(R.drawable.new_mail);
-
-// Create a WearablesNotification.Builder to add special functionality for wearables
-Notification notification =
-        new WearableNotifications.Builder(notificationBuilder)
-        .setHintHideIcon(true)
-        .build();
-</pre>
-
-<p>The <a href="/reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html#setBigActionIcon(int)">
-  <code>setHintHideIcon()</code></a> method removes your app icon from the notification card.
-  This method is just one example of new notification features available from the
-  <a href="/reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html"
-  ><code>WearableNotifications.Builder</code></a> class.</p>
-
-<p>When you want to deliver your notifications, be certain to always use the
-  <a href="/reference/android/preview/support/v4/app/NotificationManagerCompat.html">
-    <code>NotificationManagerCompat</code></a> API:</p>
-
-<pre>
-// Get an instance of the NotificationManager service
-NotificationManagerCompat notificationManager =
-        NotificationManagerCompat.from(this);
-
-// Build the notification and issues it with notification manager.
-notificationManager.notify(notificationId, notification);
-</pre>
-
-<p>If you instead use the framework's <code><a href="/reference/android/app/NotificationManager.html">NotificationManager</a></code>, some
-features from <a href="/reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html"><code>WearableNotifications.Builder</code></a>
-will not work.</p>
-
-<p>To continue enhancing your notifications for wearables using
-  <a href="/reference/android/preview/support/wearable/notifications/WearableNotifications.Builder"
-  ><code>WearableNotifications.Builder</code></a> and other APIs in the
-  preview support library, see the following developer guides:</p>
-
-  <dl>
-    <dt><a href="/wear/notifications/remote-input.html">Receiving Voice Input
-from a Notification</a></dt>
-      <dd>Add an action that receives voice input from the user and delivers the
-transcribed message to your app.</dd>
-    <dt><a href="/wear/notifications/pages.html">Adding Pages to a Notification</a></dt>
-      <dd>Add additional pages of information that are visible when the user
-swipes to the left.</dd>
-    <dt><a href="/wear/notifications/stacks.html">Stacking Notifications</a></dt>
-      <dd>Place all similar notifications from your app in a stack, allowing each to be
-viewed individually without adding multiple cards to the card stream.</dd>
-  </dl>
-
-
-<div class="next-docs">
-
-<div class="col-12">
-  <h2 class="norule">You might also want to read:</h2>
-  <dl>
-    <dt><a href="/training/notify-user/index.html">Notifying the User</a></dt>
-    <dd>Learn more about how to create notifications.</dd>
-    <dt><a href="/guide/components/intents-filters.html">Intents and Intent Filters</a></dt>
-    <dd>Learn everything you need to know about the <code><a href="/reference/android/content/Intent.html">Intent</a></code>
-APIs, used by notificaton actions.</dd>
-  </dl>
-</div>
-</div>
-
-
-</body>
-</html>
-
-    </div>
-
-      <div class="content-footer layout-content-row"
-                    itemscope itemtype="http://schema.org/SiteNavigationElement">
-        <div class="layout-content-col col-9" style="padding-top:4px">
-          
-            <div class="g-plusone" data-size="medium"></div>
-          
-        </div>
-        
-        <div class="paging-links layout-content-col col-4">
-          
-        </div>
-        
-      </div>
-
-      
-      
-
-  </div> <!-- end jd-content -->
-
-<div id="footer" class="wrap" >
-        
-
-  <div id="copyright">
-    
-  Except as noted, this content is 
-  licensed under <a href="http://creativecommons.org/licenses/by/2.5/">
-  Creative Commons Attribution 2.5</a>. For details and 
-  restrictions, see the <a href="/license.html">Content 
-  License</a>.
-  </div>
-
-
-  <div id="footerlinks">
-    
-  <p>
-    <a href="/about/index.html">About Android</a>&nbsp;&nbsp;|&nbsp;
-    <a href="/legal.html">Legal</a>&nbsp;&nbsp;|&nbsp;
-    <a href="/support.html">Support</a>
-  </p>
-  </div>
-
-</div> <!-- end footer -->
-</div><!-- end doc-content -->
-
-</div> <!-- end body-content --> 
-
-
-
-
-
-
-<!-- Start of Tag -->
-<script type="text/javascript">
-var axel = Math.random() + "";
-var a = axel * 10000000000000;
-document.write('<iframe src="https://2507573.fls.doubleclick.net/activityi;src=2507573;type=other026;cat=googl348;ord=' + a + '?" width="1" height="1" frameborder="0" style="display:none"></iframe>');
-</script>
-<noscript>
-<iframe src="https://2507573.fls.doubleclick.net/activityi;src=2507573;type=other026;cat=googl348;ord=1?" width="1" height="1" frameborder="0" style="display:none"></iframe>
-</noscript>
-<!-- End of Tag -->
-</body>
-</html>
-
-
-
diff --git a/docs/html/wear/notifications/creating.jd b/docs/html/wear/notifications/creating.jd
new file mode 100644
index 0000000..ce9e117
--- /dev/null
+++ b/docs/html/wear/notifications/creating.jd
@@ -0,0 +1,289 @@
+page.title=Creating Notifications for Android Wear
+
+@jd:body
+
+
+<p>When an Android device such as a phone or tablet is connected to an Android wearable,
+all notifications are shared between the devices by default. On the Android wearable, each
+notification appears as a new card in the <a href="{@docRoot}wear/design/user-interface.html#Stream"
+>context stream</a>.</p>
+
+<img src="{@docRoot}wear/images/notification_phone@2x.png" width="700" height="265" />
+
+
+<p>So without any effort, your app notifications are available to users on Android Wear.
+However, you can enhance the user experience in several ways. For instance,
+if users may respond to a notification by entering text, such as to reply to
+a message, you can add the ability for users to reply by voice directly from the
+wearable.</p>
+
+<p>To help you provide the best user experience
+for your notifications on Android Wear, this guide shows you how to
+build notifications using standard templates in
+the {@link android.support.v4.app.NotificationCompat.Builder} APIs, plus how to begin
+extending your notification's capabilities for the wearable user experience.</p>
+
+<p class="note"><strong>Note:</strong>
+Notifications using {@link android.widget.RemoteViews} are stripped of custom
+layouts and the system uses only the text and icons in the
+{@link android.app.Notification} object to
+display the notification in a card. However, custom card layouts will be supported by
+the official Android Wear SDK that is coming later.</p>
+</div>
+
+
+
+
+<h2 id="Import">Import the Necessary Classes</h2>
+
+<p>To begin development, you must first complete the instructions in the <a
+href="{@docRoot}wear/preview/start.html">Get Started with the Developer Preview</a> document.
+As mentioned in that document, your app must include
+both the <a href="http://developer.android.com/tools/support-library/features.html#v4">v4 support
+library</a> and the Developer Preview support library. So to get started,
+you should include the following imports in your project code:</p>
+
+<pre>
+import android.preview.support.wearable.notifications.*;
+import android.preview.support.v4.app.NotificationManagerCompat;
+import android.support.v4.app.NotificationCompat;
+</pre>
+
+<p class="caution"><strong>Caution:</strong>
+The APIs in the current Android Wear Developer Preview are intended for <b>development and testing purposes only</b>, not for production apps. Google may change this Developer Preview significantly prior to the official release of the Android Wear SDK. You may not publicly distribute or ship any application using this Developer Preview, as this Developer Preview will no longer be supported after the official SDK is released (which will cause applications based only on the Developer Preview to break).</p>
+
+
+
+<h2 id="NotificationBuilder">Create Notifications with the Notification Builder</h2>
+
+<p>The <a href="http://developer.android.com/tools/support-library/features.html#v4">v4
+support library</a> allows you to create notifications using the latest notification features
+such as action buttons and large icons, while remaining compatible with Android 1.6 (API level
+4) and higher.</p>
+
+
+<p>For example, here's some code that creates and issues a notification using the
+{@link android.support.v4.app.NotificationCompat} APIs combined with the new
+<a href="{@docRoot}reference/android/preview/support/v4/app/NotificationManagerCompat.html">
+<code>NotificationManagerCompat</code></a> API:</p>
+
+
+<pre>
+int notificationId = 001;
+// Build intent for notification content
+Intent viewIntent = new Intent(this, ViewEventActivity.class);
+viewIntent.putExtra(EXTRA_EVENT_ID, eventId);
+PendingIntent viewPendingIntent =
+        PendingIntent.getActivity(this, 0, viewIntent, 0);
+
+NotificationCompat.Builder notificationBuilder =
+        new NotificationCompat.Builder(this)
+        .setSmallIcon(R.drawable.ic_event)
+        .setContentTitle(eventTitle)
+        .setContentText(eventLocation)
+        .setContentIntent(viewPendingIntent);
+
+// Get an instance of the NotificationManager service
+NotificationManagerCompat notificationManager =
+        NotificationManagerCompat.from(this);
+
+// Build the notification and issues it with notification manager.
+notificationManager.notify(notificationId, notificationBuilder.build());
+</pre>
+
+<p>When this notification appears on a handheld device, the user can invoke the
+{@link android.app.PendingIntent}
+specified by the {@link android.support.v4.app.NotificationCompat.Builder#setContentIntent
+setContentIntent()} method by touching the notification. When this
+notification appears on an Android wearable, the user can swipe the notification to the left to
+reveal the <strong>Open</strong> action, which invokes the intent on the handheld device.</p>
+
+
+
+
+
+
+<img src="{@docRoot}wear/images/circle_email_action.png" height="200" style="float:right;clear:right;margin:0 0 20px 60px" />
+
+<h2 id="ActionButtons">Add Action Buttons</h2>
+
+<p>In addition to the primary content action defined by
+{@link android.support.v4.app.NotificationCompat.Builder#setContentIntent
+setContentIntent()}, you can add other actions by passing a {@link android.app.PendingIntent} to
+the {@link android.support.v4.app.NotificationCompat.Builder#addAction
+addAction()} method.</p>
+
+<p>For example, the following code shows the same type of notification from above, but adds an
+action to view the event location on a map.</p>
+
+<pre style="clear:right">
+// Build an intent for an action to view a map
+Intent mapIntent = new Intent(Intent.ACTION_VIEW);
+Uri geoUri = Uri.parse("geo:0,0?q=" + Uri.encode(location));
+mapIntent.setData(geoUri);
+PendingIntent mapPendingIntent =
+        PendingIntent.getActivity(this, 0, mapIntent, 0);
+
+NotificationCompat.Builder notificationBuilder =
+        new NotificationCompat.Builder(this)
+        .setSmallIcon(R.drawable.ic_event)
+        .setContentTitle(eventTitle)
+        .setContentText(eventLocation)
+        .setContentIntent(viewPendingIntent)
+        <b>.addAction(R.drawable.ic_map,
+                getString(R.string.map), mapPendingIntent);</b>
+</pre>
+
+<p>On a handheld device, the action appears as an
+additional button attached to the notification. On an Android wearable, the action appears as
+a large button when the user swipes the notification to the left. When the user taps the action,
+the associated {@link android.content.Intent} is invoked on the handheld device.</p>
+
+<p class="note"><strong>Tip:</strong> If your notifications includes a "Reply" action
+  (such as for a messaging app), you can enhance the behavior by enabling
+  voice input replies directly from the Android wearable. For more information, read
+  <a href="{@docRoot}wear/notifications/remote-input.html">Receiving Voice Input from a Notification</a>.
+</p>
+
+<p>For details about designing action buttons (including the icon specifications), see the
+<a href="{@docRoot}wear/design/index.html#NotifictionActions">Design Principles of Android
+Wear</a>.</p>
+
+
+<h2 id="BigView">Add a Big View</h2>
+
+<img src="{@docRoot}wear/images/06_images.png" height="200" style="float:right;margin:0 0 20px 40px" />
+
+<p>You can insert extended text content
+to your notification by adding one of the "big view" styles to your notification. On a
+handheld device, users can see the big view content by expanding the notification,
+while on Android Wear, the big view content is visible by default.</p>
+
+<p>To add the extended content to your notification, call {@link
+android.support.v4.app.NotificationCompat.Builder#setStyle setStyle()} on the {@link
+android.support.v4.app.NotificationCompat.Builder} object, passing it an instance of either
+{@link android.support.v4.app.NotificationCompat.BigTextStyle BigTextStyle} or
+{@link android.support.v4.app.NotificationCompat.InboxStyle InboxStyle}.</p>
+
+<p>For example, the following code adds an instance of
+{@link android.support.v4.app.NotificationCompat.BigTextStyle} to the event notification,
+in order to include the complete event description (which includes more text than can fit
+into the space provided for {@link android.support.v4.app.NotificationCompat.Builder#setContentText
+setContentText()}).</p>
+
+
+<pre style="clear:right">
+// Specify the 'big view' content to display the long
+// event description that may not fit the normal content text.
+BigTextStyle bigStyle = new NotificationCompat.BigTextStyle();
+bigStyle.bigText(eventDescription);
+
+NotificationCompat.Builder notificationBuilder =
+        new NotificationCompat.Builder(this)
+        .setSmallIcon(R.drawable.ic_event)
+        .setLargeIcon(BitmapFractory.decodeResource(
+                getResources(), R.drawable.notif_background))
+        .setContentTitle(eventTitle)
+        .setContentText(eventLocation)
+        .setContentIntent(viewPendingIntent)
+        .addAction(R.drawable.ic_map,
+                getString(R.string.map), mapPendingIntent)
+        <b>.setStyle(bigStyle);</b>
+</pre>
+
+<p>Notice that you can add a large background image to any notification using the
+{@link android.support.v4.app.NotificationCompat.Builder#setLargeIcon setLargeIcon()}
+method. For more information about designing notifications with large images, see the
+<a href="{@docRoot}wear/design/index.html#Images">Design Principles of Android
+Wear</a>.</p>
+
+
+
+<h2 id="NewFeatures">Add New Features for Wearables</h2>
+
+<p>The Android Wear preview support library provides new APIs that
+  allow you to enhance the user experience for notifications on a wearable device. For example,
+  you can add additional pages of content that users can view by swiping to the left, or add the ability
+for users to deliver your app a text response using voice input.</p>
+
+<p>To use these new APIs, pass your instance of
+{@link android.support.v4.app.NotificationCompat.Builder} to the
+  <a href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html#WearableNotifications.Builder(android.content.Context)"> <code>WearableNotifications.Builder()</code></a> constructor. You can then add new
+features to your notification using the
+  <a href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html"
+  ><code>WearableNotifications.Builder</code></a> methods. For example:</p>
+
+<pre>
+// Create a NotificationCompat.Builder for standard notification features
+NotificationCompat.Builder notificationBuilder =
+        new NotificationCompat.Builder(mContext)
+        .setContentTitle("New mail from " + sender.toString())
+        .setContentText(subject)
+        .setSmallIcon(R.drawable.new_mail);
+
+// Create a WearablesNotification.Builder to add special functionality for wearables
+Notification notification =
+        new WearableNotifications.Builder(notificationBuilder)
+        .setHintHideIcon(true)
+        .build();
+</pre>
+
+<p>The <a href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html#setBigActionIcon(int)">
+  <code>setHintHideIcon()</code></a> method removes your app icon from the notification card.
+  This method is just one example of new notification features available from the
+  <a href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html"
+  ><code>WearableNotifications.Builder</code></a> class.</p>
+
+<p>When you want to deliver your notifications, be certain to always use the
+  <a href="{@docRoot}reference/android/preview/support/v4/app/NotificationManagerCompat.html">
+    <code>NotificationManagerCompat</code></a> API:</p>
+
+<pre>
+// Get an instance of the NotificationManager service
+NotificationManagerCompat notificationManager =
+        NotificationManagerCompat.from(this);
+
+// Build the notification and issues it with notification manager.
+notificationManager.notify(notificationId, notification);
+</pre>
+
+<p>If you instead use the framework's {@link android.app.NotificationManager}, some
+features from <a href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html"><code>WearableNotifications.Builder</code></a>
+will not work.</p>
+
+<p>To continue enhancing your notifications for wearables using
+  <a href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html"
+  ><code>WearableNotifications.Builder</code></a> and other APIs in the
+  preview support library, see the following developer guides:</p>
+
+  <dl>
+    <dt><a href="{@docRoot}wear/notifications/remote-input.html">Receiving Voice Input
+from a Notification</a></dt>
+      <dd>Add an action that receives voice input from the user and delivers the
+transcribed message to your app.</dd>
+    <dt><a href="{@docRoot}wear/notifications/pages.html">Adding Pages to a Notification</a></dt>
+      <dd>Add additional pages of information that are visible when the user
+swipes to the left.</dd>
+    <dt><a href="{@docRoot}wear/notifications/stacks.html">Stacking Notifications</a></dt>
+      <dd>Place all similar notifications from your app in a stack, allowing each to be
+viewed individually without adding multiple cards to the card stream.</dd>
+  </dl>
+
+
+<div class="next-docs">
+
+<div class="col-12">
+  <h2 class="norule">You might also want to read:</h2>
+  <dl>
+    <dt><a href="{@docRoot}training/notify-user/index.html">Notifying the User</a></dt>
+    <dd>Learn more about how to create notifications.</dd>
+    <dt><a href="{@docRoot}guide/components/intents-filters.html">Intents and Intent Filters</a></dt>
+    <dd>Learn everything you need to know about the {@link android.content.Intent}
+APIs, used by notificaton actions.</dd>
+  </dl>
+</div>
+</div>
+
+
+</body>
+</html>
diff --git a/docs/html/wear/notifications/pages.html b/docs/html/wear/notifications/pages.html
deleted file mode 100644
index ce568eb..0000000
--- a/docs/html/wear/notifications/pages.html
+++ /dev/null
@@ -1,500 +0,0 @@
-<!DOCTYPE html>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-<html>
-<head>
-
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
-<meta name="viewport" content="width=device-width" />
-
-<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
-<title>Adding Pages to a Notification | Android Developers</title>
-
-<!-- STYLESHEETS -->
-<link rel="stylesheet"
-href="//fonts.googleapis.com/css?family=Roboto:light,regular,medium,thin,italic,mediumitalic,bold" title="roboto">
-<link href="/assets/css/default.css" rel="stylesheet" type="text/css">
-
-
-
-<!-- JAVASCRIPT -->
-<script src="//www.google.com/jsapi" type="text/javascript"></script>
-<script src="/assets/js/android_3p-bundle.js" type="text/javascript"></script>
-<script type="text/javascript">
-  var toRoot = "/";
-  var metaTags = [];
-  var devsite = false;
-</script>
-<script src="/assets/js/docs.js" type="text/javascript"></script>
-
-<script type="text/javascript">
-  var _gaq = _gaq || [];
-  _gaq.push(['_setAccount', 'UA-5831155-1']);
-  _gaq.push(['_trackPageview']);
-
-  (function() {
-    var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
-    ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
-    var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
-  })();
-</script>
-</head>
-
-<body class="gc-documentation 
-  " itemscope itemtype="http://schema.org/Article">
-
-
-  
-<a name="top"></a>
-
-    <!-- Header -->
-    <div id="header">
-        <div class="wrap" id="header-wrap">
-          <div class="col-3 logo-wear">
-          <a href="/wear/index.html">
-            <img src="/wear/images/android-wear.png" height="16" alt="Android Wear" />
-          </a>
-          </div>
-
-
-	<div class="col-8" style="margin:0"><h1 style="margin:1px 0 0 20px;padding:0;line-height:16px;
-  color:#666;font-weight:100;font-size:24px;">Developer Preview</h1></div>
-            
-
-          <!-- New Search -->
-          <div class="menu-container">
-            <div class="moremenu">
-	        <div id="more-btn"></div>
-	    </div>
-  <div class="morehover" id="moremenu">
-    <div class="top"></div>
-    <div class="mid">
-      <div class="header">Links</div>
-      <ul>
-        <li><a href="https://play.google.com/apps/publish/">Google Play Developer Console</a></li>
-        <li><a href="http://android-developers.blogspot.com/">Android Developers Blog</a></li>
-        <li><a href="/about/index.html">About Android</a></li>
-      </ul>
-      <div class="header">Android Sites</div>
-      <ul>
-        <li><a href="http://www.android.com">Android.com</a></li>
-        <li class="active"><a>Android Developers</a></li>
-        <li><a href="http://source.android.com">Android Open Source Project</a></li>
-      </ul>
-      
-      
-      
-        <div class="header">Language</div>
-          <div id="language" class="locales">
-            <select name="language" onChange="changeLangPref(this.value, true)">
-                <option value="en">English</option>
-                <option value="es">Español</option>
-                <option value="ja">日本語</option>
-                <option value="ko">한국어</option>
-                <option value="ru">Русский</option>
-                <option value="zh-cn">中文 (中国)</option>
-                <option value="zh-tw">中文 (台灣)</option>
-            </select>
-          </div>
-        <script type="text/javascript">
-          <!--
-          loadLangPref();
-            //-->
-        </script>
-      
-      
-
-
-      <br class="clearfix" />
-    </div><!-- end mid -->
-    <div class="bottom"></div>
-  </div><!-- end morehover -->
-
-  <div class="search" id="search-container">
-    <div class="search-inner">
-      <div id="search-btn"></div>
-      <div class="left"></div>
-      <form onsubmit="return submit_search()">
-        <input id="search_autocomplete" type="text" value="" autocomplete="off" name="q"
-onfocus="search_focus_changed(this, true)" onblur="search_focus_changed(this, false)"
-onkeydown="return search_changed(event, true, '/')" 
-onkeyup="return search_changed(event, false, '/')" />
-      </form>
-      <div class="right"></div>
-        <a class="close hide">close</a>
-        <div class="left"></div>
-        <div class="right"></div>
-    </div>
-  </div><!--  end search -->
-
-  <div class="search_filtered_wrapper reference">
-    <div class="suggest-card reference no-display">
-      <ul class="search_filtered">
-      </ul>
-    </div>
-  </div>
-
-  <div class="search_filtered_wrapper docs">
-    <div class="suggest-card dummy no-display">&nbsp;</div>
-    <div class="suggest-card develop no-display">
-      <ul class="search_filtered">
-      </ul>
-      <div class="child-card guides no-display">
-      </div>
-      <div class="child-card training no-display">
-      </div>
-      <div class="child-card samples no-display">
-      </div>
-    </div>
-    <div class="suggest-card design no-display">
-      <ul class="search_filtered">
-      </ul>
-    </div>
-    <div class="suggest-card distribute no-display">
-      <ul class="search_filtered">
-      </ul>
-    </div>
-  </div><!-- end search_filtered_wrapper -->
-
-  </div>
-  <!-- end menu_container -->
-
-
-        </div><!-- end header-wrap -->
-    </div>
-    <!-- /Header -->
-
-
-  <div id="searchResults" class="wrap" style="display:none;">
-          <h2 id="searchTitle">Results</h2>
-          <div id="leftSearchControl" class="search-control">Loading...</div>
-  </div>
-
-  
-
-  
-
-  <div class="wrap clearfix" id="body-content">
-    <div class="col-4" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
-      <div id="devdoc-nav" class="scroll-pane">
-<a class="totop" href="#top" data-g-event="left-nav-top">to top</a>
-
-<ul id="nav">
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/wear/preview/start.html">Get Started
-      </a></div>
-  </li>
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/wear/design/user-interface.html">UI Overview
-      </a></div>
-  </li>
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/wear/design/index.html">Design Principles
-      </a></div>
-  </li>
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/wear/notifications/creating.html">Creating Notifications for Android Wear
-      </a></div>
-  </li>
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/wear/notifications/remote-input.html">Receiving Voice Input from a Notification
-      </a></div>
-  </li>
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/wear/notifications/pages.html">Adding Pages to a Notification
-      </a></div>
-  </li>
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/wear/notifications/stacks.html">Stacking Notifications
-      </a></div>
-  </li>
-
-  <li class="nav-section">
-    <div class="nav-section-header"><a href="/reference/android/preview/support/package-summary.html">Notification Reference</a></div>
-    <ul class="tree-list-children">
-<li class="nav-section">
-<div class="nav-section-header-ref"><span class="tree-list-subtitle package" title="android.preview.support.v4.app">android.preview.support.v4.app</span></div>
-  <ul>
-<li><a href="/reference/android/preview/support/v4/app/NotificationManagerCompat.html">NotificationManagerCompat</a></li>
-  </ul>
-</li>
-
-<li class="nav-section">
-<div class="nav-section-header-ref"><span class="tree-list-subtitle package" title="android.preview.support.wearable.notifications">android.preview.support.wearable.notifications</span></div>
-<ul>
-
-<li><a href="/reference/android/preview/support/wearable/notifications/RemoteInput.html">RemoteInput</a></li>
-<li><a href="/reference/android/preview/support/wearable/notifications/RemoteInput.Builder.html" >RemoteInput.Builder</a></li>
-
-<li><a href="/reference/android/preview/support/wearable/notifications/WearableNotifications.html">WearableNotifications</a></li>
-
-<li><a href="/reference/android/preview/support/wearable/notifications/WearableNotifications.Action.html">WearableNotifications.Action</a></li>
-
-<li><a href="/reference/android/preview/support/wearable/notifications/WearableNotifications.Action.Builder.html">WearableNotifications.Action.Builder</a></li>
-
-<li><a href="/reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html">WearableNotifications.Builder</a></li>
-	</ul>
-  </li>
-</ul>
-</li>
-
-
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/wear/license.html">License Agreement</a></div>
-  </li>
-
-
-</ul>
-
-        
-
-      </div>
-    </div> <!-- end side-nav -->
-    <script>
-      $(document).ready(function() {
-        scrollIntoView("devdoc-nav");
-        });
-    </script>
-
-
-
-
-<div class="col-12" id="doc-col" >
-
-
-  
-    
-      
-        <h1 itemprop="name" >Adding Pages to a Notification</h1>
-      
-    
-  
-
-
-  
-  <div id="jd-content">
-
-
-    <div class="jd-descr" itemprop="articleBody">
-    <img src="/wear/images/09_pages.png" height="200" style="float:right;margin:0 0 20px 40px" />
-<img src="/wear/images/08_pages.png" height="200" style="float:right;margin:0 0 20px 40px" />
-
-<p>When you'd like to provide more information without requiring users
-to open your app on their handheld device, you can
-add one or more pages to the notification on Android Wear. The additional pages
-appear immediately to the right of the main notification card.
-For information about when to use and how to design
-multiple pages, see the
-<a href="/wear/design/index.html#NotificationPages">Design Principles of Android
-Wear</a>.</p>
-
-
-<p>When creating a notification with multiple pages, start by creating the main notification
-(the first page) the way you'd like the notification to appear on a phone
-or tablet. Then, add pages one at a time with the
-<a href="/reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html#addPage(android.app.Notification)">
-<code>addPage()</code></a> method, or add multiple pages in a <code><a href="/reference/java/util/Collection.html">Collection</a></code> with the
-<a href="/reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html#addPages(java.util.Collection<android.app.Notification>)">
-<code>addPages()</code></a> method.</p>
-
-
-<p>For example, here's some code that adds a second page to a notification:</p>
-
-<pre>
-// Create builder for the main notification
-NotificationCompat.Builder notificationBuilder =
-        new NotificationCompat.Builder(this)
-        .setSmallIcon(R.drawable.new_message)
-        .setContentTitle("Page 1")
-        .setContentText("Short message")
-        .setContentIntent(viewPendingIntent);
-
-// Create a big text style for the second page
-BigTextStyle secondPageStyle = new NotificationCompat.BigTextStyle();
-secondPageStyle.setBigContentTitle("Page 2")
-               .bigText("A lot of text...");
-
-// Create second page notification
-Notification secondPageNotification =
-        new NotificationCompat.Builder(this)
-        .setStyle(secondPageStyle)
-        .build();
-
-// Create main notification and add the second page
-Notification twoPageNotification =
-        new WearableNotifications.Builder(notificationBuilder)
-        .addPage(secondPageNotification)
-        .build();
-</pre>
-
-
-
-
-</body>
-</html>
-
-    </div>
-
-      <div class="content-footer layout-content-row"
-                    itemscope itemtype="http://schema.org/SiteNavigationElement">
-        <div class="layout-content-col col-9" style="padding-top:4px">
-          
-            <div class="g-plusone" data-size="medium"></div>
-          
-        </div>
-        
-        <div class="paging-links layout-content-col col-4">
-          
-        </div>
-        
-      </div>
-
-      
-      
-
-  </div> <!-- end jd-content -->
-
-<div id="footer" class="wrap" >
-        
-
-  <div id="copyright">
-    
-  Except as noted, this content is 
-  licensed under <a href="http://creativecommons.org/licenses/by/2.5/">
-  Creative Commons Attribution 2.5</a>. For details and 
-  restrictions, see the <a href="/license.html">Content 
-  License</a>.
-  </div>
-
-
-  <div id="footerlinks">
-    
-  <p>
-    <a href="/about/index.html">About Android</a>&nbsp;&nbsp;|&nbsp;
-    <a href="/legal.html">Legal</a>&nbsp;&nbsp;|&nbsp;
-    <a href="/support.html">Support</a>
-  </p>
-  </div>
-
-</div> <!-- end footer -->
-</div><!-- end doc-content -->
-
-</div> <!-- end body-content --> 
-
-
-
-
-
-
-<!-- Start of Tag -->
-<script type="text/javascript">
-var axel = Math.random() + "";
-var a = axel * 10000000000000;
-document.write('<iframe src="https://2507573.fls.doubleclick.net/activityi;src=2507573;type=other026;cat=googl348;ord=' + a + '?" width="1" height="1" frameborder="0" style="display:none"></iframe>');
-</script>
-<noscript>
-<iframe src="https://2507573.fls.doubleclick.net/activityi;src=2507573;type=other026;cat=googl348;ord=1?" width="1" height="1" frameborder="0" style="display:none"></iframe>
-</noscript>
-<!-- End of Tag -->
-</body>
-</html>
-
-
-
diff --git a/docs/html/wear/notifications/pages.jd b/docs/html/wear/notifications/pages.jd
new file mode 100644
index 0000000..558f7b8
--- /dev/null
+++ b/docs/html/wear/notifications/pages.jd
@@ -0,0 +1,61 @@
+page.title=Adding Pages to a Notification
+
+@jd:body
+
+
+<img src="{@docRoot}wear/images/09_pages.png" height="200" style="float:right;margin:0 0 20px 40px" />
+<img src="{@docRoot}wear/images/08_pages.png" height="200" style="float:right;margin:0 0 20px 40px" />
+
+<p>When you'd like to provide more information without requiring users
+to open your app on their handheld device, you can
+add one or more pages to the notification on Android Wear. The additional pages
+appear immediately to the right of the main notification card.
+For information about when to use and how to design
+multiple pages, see the
+<a href="{@docRoot}wear/design/index.html#NotificationPages">Design Principles of Android
+Wear</a>.</p>
+
+
+<p>When creating a notification with multiple pages, start by creating the main notification
+(the first page) the way you'd like the notification to appear on a phone
+or tablet. Then, add pages one at a time with the
+<a href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html#addPage(android.app.Notification)">
+<code>addPage()</code></a> method, or add multiple pages in a {@link java.util.Collection} with the
+<a href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html#addPages(java.util.Collection<android.app.Notification>)">
+<code>addPages()</code></a> method.</p>
+
+
+<p>For example, here's some code that adds a second page to a notification:</p>
+
+<pre>
+// Create builder for the main notification
+NotificationCompat.Builder notificationBuilder =
+        new NotificationCompat.Builder(this)
+        .setSmallIcon(R.drawable.new_message)
+        .setContentTitle("Page 1")
+        .setContentText("Short message")
+        .setContentIntent(viewPendingIntent);
+
+// Create a big text style for the second page
+BigTextStyle secondPageStyle = new NotificationCompat.BigTextStyle();
+secondPageStyle.setBigContentTitle("Page 2")
+               .bigText("A lot of text...");
+
+// Create second page notification
+Notification secondPageNotification =
+        new NotificationCompat.Builder(this)
+        .setStyle(secondPageStyle)
+        .build();
+
+// Create main notification and add the second page
+Notification twoPageNotification =
+        new WearableNotifications.Builder(notificationBuilder)
+        .addPage(secondPageNotification)
+        .build();
+</pre>
+
+
+
+
+</body>
+</html>
diff --git a/docs/html/wear/notifications/remote-input.html b/docs/html/wear/notifications/remote-input.html
deleted file mode 100644
index c8f6621..0000000
--- a/docs/html/wear/notifications/remote-input.html
+++ /dev/null
@@ -1,652 +0,0 @@
-<!DOCTYPE html>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-<html>
-<head>
-
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
-<meta name="viewport" content="width=device-width" />
-
-<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
-<title>Receiving Voice Input from a Notification | Android Developers</title>
-
-<!-- STYLESHEETS -->
-<link rel="stylesheet"
-href="//fonts.googleapis.com/css?family=Roboto:light,regular,medium,thin,italic,mediumitalic,bold" title="roboto">
-<link href="/assets/css/default.css" rel="stylesheet" type="text/css">
-
-
-
-<!-- JAVASCRIPT -->
-<script src="//www.google.com/jsapi" type="text/javascript"></script>
-<script src="/assets/js/android_3p-bundle.js" type="text/javascript"></script>
-<script type="text/javascript">
-  var toRoot = "/";
-  var metaTags = [];
-  var devsite = false;
-</script>
-<script src="/assets/js/docs.js" type="text/javascript"></script>
-
-<script type="text/javascript">
-  var _gaq = _gaq || [];
-  _gaq.push(['_setAccount', 'UA-5831155-1']);
-  _gaq.push(['_trackPageview']);
-
-  (function() {
-    var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
-    ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
-    var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
-  })();
-</script>
-</head>
-
-<body class="gc-documentation 
-  " itemscope itemtype="http://schema.org/Article">
-
-
-  
-<a name="top"></a>
-
-    <!-- Header -->
-    <div id="header">
-        <div class="wrap" id="header-wrap">
-          <div class="col-3 logo-wear">
-          <a href="/wear/index.html">
-            <img src="/wear/images/android-wear.png" height="16" alt="Android Wear" />
-          </a>
-          </div>
-
-
-	<div class="col-8" style="margin:0"><h1 style="margin:1px 0 0 20px;padding:0;line-height:16px;
-  color:#666;font-weight:100;font-size:24px;">Developer Preview</h1></div>
-            
-
-          <!-- New Search -->
-          <div class="menu-container">
-            <div class="moremenu">
-	        <div id="more-btn"></div>
-	    </div>
-  <div class="morehover" id="moremenu">
-    <div class="top"></div>
-    <div class="mid">
-      <div class="header">Links</div>
-      <ul>
-        <li><a href="https://play.google.com/apps/publish/">Google Play Developer Console</a></li>
-        <li><a href="http://android-developers.blogspot.com/">Android Developers Blog</a></li>
-        <li><a href="/about/index.html">About Android</a></li>
-      </ul>
-      <div class="header">Android Sites</div>
-      <ul>
-        <li><a href="http://www.android.com">Android.com</a></li>
-        <li class="active"><a>Android Developers</a></li>
-        <li><a href="http://source.android.com">Android Open Source Project</a></li>
-      </ul>
-      
-      
-      
-        <div class="header">Language</div>
-          <div id="language" class="locales">
-            <select name="language" onChange="changeLangPref(this.value, true)">
-                <option value="en">English</option>
-                <option value="es">Español</option>
-                <option value="ja">日本語</option>
-                <option value="ko">한국어</option>
-                <option value="ru">Русский</option>
-                <option value="zh-cn">中文 (中国)</option>
-                <option value="zh-tw">中文 (台灣)</option>
-            </select>
-          </div>
-        <script type="text/javascript">
-          <!--
-          loadLangPref();
-            //-->
-        </script>
-      
-      
-
-
-      <br class="clearfix" />
-    </div><!-- end mid -->
-    <div class="bottom"></div>
-  </div><!-- end morehover -->
-
-  <div class="search" id="search-container">
-    <div class="search-inner">
-      <div id="search-btn"></div>
-      <div class="left"></div>
-      <form onsubmit="return submit_search()">
-        <input id="search_autocomplete" type="text" value="" autocomplete="off" name="q"
-onfocus="search_focus_changed(this, true)" onblur="search_focus_changed(this, false)"
-onkeydown="return search_changed(event, true, '/')" 
-onkeyup="return search_changed(event, false, '/')" />
-      </form>
-      <div class="right"></div>
-        <a class="close hide">close</a>
-        <div class="left"></div>
-        <div class="right"></div>
-    </div>
-  </div><!--  end search -->
-
-  <div class="search_filtered_wrapper reference">
-    <div class="suggest-card reference no-display">
-      <ul class="search_filtered">
-      </ul>
-    </div>
-  </div>
-
-  <div class="search_filtered_wrapper docs">
-    <div class="suggest-card dummy no-display">&nbsp;</div>
-    <div class="suggest-card develop no-display">
-      <ul class="search_filtered">
-      </ul>
-      <div class="child-card guides no-display">
-      </div>
-      <div class="child-card training no-display">
-      </div>
-      <div class="child-card samples no-display">
-      </div>
-    </div>
-    <div class="suggest-card design no-display">
-      <ul class="search_filtered">
-      </ul>
-    </div>
-    <div class="suggest-card distribute no-display">
-      <ul class="search_filtered">
-      </ul>
-    </div>
-  </div><!-- end search_filtered_wrapper -->
-
-  </div>
-  <!-- end menu_container -->
-
-
-        </div><!-- end header-wrap -->
-    </div>
-    <!-- /Header -->
-
-
-  <div id="searchResults" class="wrap" style="display:none;">
-          <h2 id="searchTitle">Results</h2>
-          <div id="leftSearchControl" class="search-control">Loading...</div>
-  </div>
-
-  
-
-  
-
-  <div class="wrap clearfix" id="body-content">
-    <div class="col-4" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
-      <div id="devdoc-nav" class="scroll-pane">
-<a class="totop" href="#top" data-g-event="left-nav-top">to top</a>
-
-<ul id="nav">
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/wear/preview/start.html">Get Started
-      </a></div>
-  </li>
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/wear/design/user-interface.html">UI Overview
-      </a></div>
-  </li>
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/wear/design/index.html">Design Principles
-      </a></div>
-  </li>
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/wear/notifications/creating.html">Creating Notifications for Android Wear
-      </a></div>
-  </li>
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/wear/notifications/remote-input.html">Receiving Voice Input from a Notification
-      </a></div>
-  </li>
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/wear/notifications/pages.html">Adding Pages to a Notification
-      </a></div>
-  </li>
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/wear/notifications/stacks.html">Stacking Notifications
-      </a></div>
-  </li>
-
-  <li class="nav-section">
-    <div class="nav-section-header"><a href="/reference/android/preview/support/package-summary.html">Notification Reference</a></div>
-    <ul class="tree-list-children">
-<li class="nav-section">
-<div class="nav-section-header-ref"><span class="tree-list-subtitle package" title="android.preview.support.v4.app">android.preview.support.v4.app</span></div>
-  <ul>
-<li><a href="/reference/android/preview/support/v4/app/NotificationManagerCompat.html">NotificationManagerCompat</a></li>
-  </ul>
-</li>
-
-<li class="nav-section">
-<div class="nav-section-header-ref"><span class="tree-list-subtitle package" title="android.preview.support.wearable.notifications">android.preview.support.wearable.notifications</span></div>
-<ul>
-
-<li><a href="/reference/android/preview/support/wearable/notifications/RemoteInput.html">RemoteInput</a></li>
-<li><a href="/reference/android/preview/support/wearable/notifications/RemoteInput.Builder.html" >RemoteInput.Builder</a></li>
-
-<li><a href="/reference/android/preview/support/wearable/notifications/WearableNotifications.html">WearableNotifications</a></li>
-
-<li><a href="/reference/android/preview/support/wearable/notifications/WearableNotifications.Action.html">WearableNotifications.Action</a></li>
-
-<li><a href="/reference/android/preview/support/wearable/notifications/WearableNotifications.Action.Builder.html">WearableNotifications.Action.Builder</a></li>
-
-<li><a href="/reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html">WearableNotifications.Builder</a></li>
-	</ul>
-  </li>
-</ul>
-</li>
-
-
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/wear/license.html">License Agreement</a></div>
-  </li>
-
-
-</ul>
-
-        
-
-      </div>
-    </div> <!-- end side-nav -->
-    <script>
-      $(document).ready(function() {
-        scrollIntoView("devdoc-nav");
-        });
-    </script>
-
-
-
-
-<div class="col-12" id="doc-col" >
-
-
-  
-    
-      
-        <h1 itemprop="name" >Receiving Voice Input from a Notification</h1>
-      
-    
-  
-
-
-  
-  <div id="jd-content">
-
-
-    <div class="jd-descr" itemprop="articleBody">
-    <img src="/wear/images/13_voicereply.png" height="200" width="169" style="float:right;margin:0 0 20px 40px" />
-
-<img src="/wear/images/03_actions.png" height="200" width="169" style="float:right;margin:0 0 20px 40px" />
-
-<p>If your notification includes an action to respond with text,
-    such as to reply to an email, it should normally launch an activity
-    on the handheld device. However, when your notification appears on an Android wearable, you can
-    allow users to dictate a reply with voice input. You can also provide pre-defined text
-    messages for the user to select.</p>
-
-<p>When the user replies with voice or selects one of the available
-messages, the system sends the message to your app on the connected handheld device.
-The message is attached as an extra in the <code><a href="/reference/android/content/Intent.html">Intent</a></code> you specified
-to be used for the notification action.</p>
-
-<p class="note"><strong>Note:</strong> When developing with the Android emulator,
-you must type text replies into the voice input field, so be sure you have enabled
-<strong>Hardware keyboard present</strong> in the AVD settings.</p>
-
-
-<h2 id="RemoteInput">Define the Remote Input</h2>
-
-<p>To create an action that supports voice input, first create an instance of
-  <a href="/reference/android/preview/support/wearable/notifications/RemoteInput.html">
-<code>RemoteInput</code></a> using the
-  <a href="/reference/android/preview/support/wearable/notifications/RemoteInput.Builder.html"><code>RemoteInput.Builder</code></a> APIs.
-    The
-  <a href="/reference/android/preview/support/wearable/notifications/RemoteInput.Builder.html"><code>RemoteInput.Builder</code></a> constructor takes a string that the system
-    will use as a key for the <code><a href="/reference/android/content/Intent.html">Intent</a></code> extra that carries the reply message
-    to your app on the handheld.</p>
-
-<p>For example, here's how to create a new
-  <a href="/reference/android/preview/support/wearable/notifications/RemoteInput.html">
-<code>RemoteInput</code></a> object that provides a custom
-    label for the voice input prompt:</p>
-
-<pre class="prettyprint">
-// Key for the string that's delivered in the action's intent
-private static final String EXTRA_VOICE_REPLY = "extra_voice_reply";
-
-String replyLabel = getResources().getString(R.string.reply_label);
-
-RemoteInput remoteInput = new RemoteInput.Builder(EXTRA_VOICE_REPLY)
-        .setLabel(replyLabel)
-        .build();
-</pre>
-
-
-<h3>Add Pre-defined Text Responses</h3>
-
-<img src="/wear/images/12_voicereply.png" height="200" style="float:right;margin:0 0 20px 40px" />
-
-<p>In addition to allowing voice input, you can
-    provide up to five text responses that the user can select for quick replies. Call
-  <a href="/reference/android/preview/support/wearable/notifications/RemoteInput.Builder.html#setChoices(java.lang.String[])"><code>setChoices()</code></a> and pass it a string array.</p>
-
-<p>For example, you may define some responses in a resource array:</p>
-
-<p class="code-caption">res/values/strings.xml</code>
-<pre class="prettyprint">
-&lt;?xml version="1.0" encoding="utf-8"?>
-&lt;resources>
-    &lt;string-array name="reply_choices">
-        &lt;item>Yes&lt;/item>
-        &lt;item>No&lt;/item>
-        &lt;item>Maybe&lt;/item>
-    &lt;/string-array>
-&lt;/resources>
-</pre>
-
-<p>Then, inflate the string array and add it to the
-  <a href="/reference/android/preview/support/wearable/notifications/RemoteInput.html"><code>RemoteInput</code></a>:</p>
-
-<pre>
-String replyLabel = getResources().getString(R.string.reply_label);
-String[] replyChoices = getResources().getStringArray(R.array.reply_choices);
-
-RemoteInput remoteInput = new RemoteInput.Builder(EXTRA_VOICE_REPLY)
-        .setLabel(replyLabel)
-        .setChoices(replyChoices)
-        .build();
-</pre>
-
-
-
-
-<h2 id="PrimaryAction">Receive Voice Input for the Primary Action</h2>
-
-<p>If "Reply" is your notification's primary action (defined by the <code><a href="/reference/android/support/v4/app/NotificationCompat.Builder.html#setContentIntent(android.app.PendingIntent)">setContentIntent()</a></code>
-method), then you should attach the
-  <a href="/reference/android/preview/support/wearable/notifications/RemoteInput.html"><code>RemoteInput</code></a> to the main action using
-  <a href="/reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html#addRemoteInputForContentIntent(android.preview.support.wearable.notifications.RemoteInput)">
-<code>addRemoteInputForContentIntent()</code></a>. For example:</p>
-
-<pre>
-// Create intent for reply action
-Intent replyIntent = new Intent(this, ReplyActivity.class);
-PendingIntent replyPendingIntent =
-        PendingIntent.getActivity(this, 0, replyIntent, 0);
-
-// Build the notification
-NotificationCompat.Builder replyNotificationBuilder =
-        new NotificationCompat.Builder(this)
-        .setSmallIcon(R.drawable.ic_new_message)
-        .setContentTitle("Message from Travis")
-        .setContentText("I love key lime pie!")
-        .setContentIntent(replyPendingIntent);
-
-// Create the remote input
-RemoteInput remoteInput = new RemoteInput.Builder(EXTRA_VOICE_REPLY)
-        .setLabel(replyLabel)
-        .build();
-
-// Create wearable notification and add remote input
-Notification replyNotification =
-        new WearableNotifications.Builder(replyNotificationBuilder)
-        .addRemoteInputForContentIntent(replyAction)
-        .build();
-</pre>
-
-
-<p>By using
-  <a href="/reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html#addRemoteInputForContentIntent(android.preview.support.wearable.notifications.RemoteInput)">
-<code>addRemoteInputForContentIntent()</code></a> to add the
-  <a href="/reference/android/preview/support/wearable/notifications/RemoteInput.html"><code>RemoteInput</code></a> object to the notification's primary action,
-the button that normally appears as an "Open" action becomes the "Reply" action
-and starts the voice input UI when users select it on Android Wear.</p>
-
-
-
-<h2 id="NewAction">Receive Voice Input for a Secondary Action</h2>
-
-<p>If the "Reply" action is not your notification's primary action and you want to enable
-voice input for a secondary action, add the
-  <a href="/reference/android/preview/support/wearable/notifications/RemoteInput.html"><code>RemoteInput</code></a> to a new action button defined by an
-  <a href="/reference/android/preview/support/wearable/notifications/Action.html">
-<code>Action</code></a> object.</p>
-
-<p>You should instantiate the
-  <a href="/reference/android/preview/support/wearable/notifications/WearableNotifications.Action.html">
-<code>Action</code></a> with the
-  <a href="/reference/android/preview/support/wearable/notifications/WearableNotifications.Action.Builder.html"><code>Action.Builder()</code></a>
-constructor, which takes an icon and text label for the action button, plus the
-<code><a href="/reference/android/app/PendingIntent.html">PendingIntent</a></code>
-the system should use to invoke your app when the user selects the action. For example:</p>
-
-<pre>
-// Create the pending intent to fire when the user selects the action
-Intent replyIntent = new Intent(this, ReplyActivity.class);
-PendingIntent pendingReplyIntent =
-        PendingIntent.getActivity(this, 0, replyIntent, 0);
-
-// Create the remote input
-RemoteInput remoteInput = new RemoteInput.Builder(EXTRA_VOICE_REPLY)
-        .setLabel(replyLabel)
-        .build();
-
-// Create the notification action
-Action replyAction = new Action.Builder(R.drawable.ic_message,
-        "Reply", pendingIntent)
-        .addRemoteInput(remoteInput)
-        .build();
-</pre>
-
-
-<p>After you add the
-  <a href="/reference/android/preview/support/wearable/notifications/RemoteInput.html"><code>RemoteInput</code></a> to the
-  <a href="/reference/android/preview/support/wearable/notifications/WearableNotifications.Action.html">
-<code>Action</code></a>, add the
-  <a href="/reference/android/preview/support/wearable/notifications/WearableNotifications.Action.html">
-<code>Action</code></a> to the
-  <a href="/reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html"><code>WearableNotifications.Builder</code></a> using
-  <a href="/reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html#addAction(Action)"><code>addAction()</code></a>.
-For example:</p>
-
-<pre>
-// Create basic notification builder
-NotificationCompat.Builder replyNotificationBuilder =
-        new NotificationCompat.Builder(this)
-        .setContentTitle("New message");
-
-// Create the notification action and add remote input
-Action replyAction = new Action.Builder(R.drawable.ic_message,
-        "Reply", pendingIntent)
-        .addRemoteInput(remoteInput)
-        .build();
-
-// Create wearable notification and add action
-Notification replyNotification =
-        new WearableNotifications.Builder(replyNotificationBuilder)
-        .addAction(replyAction)
-        .build();
-</pre>
-
-<p>Now, when the user selects "Reply" from an Android wearable, the system prompts the user
-    for voice input (and shows the list of pre-defined replies, if provided).
-    Once the user completes a response, the system invokes
-    the <code><a href="/reference/android/content/Intent.html">Intent</a></code> attached to the action and adds the
-<code>EXTRA_VOICE_REPLY</code> extra (the string
-    you passed to the
-  <a href="/reference/android/preview/support/wearable/notifications/RemoteInput.Builder.html"><code>RemoteInput.Builder</code></a> constructor)
-    with the user's message as the string value.</p>
-
-
-
-
-</body>
-</html>
-
-    </div>
-
-      <div class="content-footer layout-content-row"
-                    itemscope itemtype="http://schema.org/SiteNavigationElement">
-        <div class="layout-content-col col-9" style="padding-top:4px">
-          
-            <div class="g-plusone" data-size="medium"></div>
-          
-        </div>
-        
-        <div class="paging-links layout-content-col col-4">
-          
-        </div>
-        
-      </div>
-
-      
-      
-
-  </div> <!-- end jd-content -->
-
-<div id="footer" class="wrap" >
-        
-
-  <div id="copyright">
-    
-  Except as noted, this content is 
-  licensed under <a href="http://creativecommons.org/licenses/by/2.5/">
-  Creative Commons Attribution 2.5</a>. For details and 
-  restrictions, see the <a href="/license.html">Content 
-  License</a>.
-  </div>
-
-
-  <div id="footerlinks">
-    
-  <p>
-    <a href="/about/index.html">About Android</a>&nbsp;&nbsp;|&nbsp;
-    <a href="/legal.html">Legal</a>&nbsp;&nbsp;|&nbsp;
-    <a href="/support.html">Support</a>
-  </p>
-  </div>
-
-</div> <!-- end footer -->
-</div><!-- end doc-content -->
-
-</div> <!-- end body-content --> 
-
-
-
-
-
-
-<!-- Start of Tag -->
-<script type="text/javascript">
-var axel = Math.random() + "";
-var a = axel * 10000000000000;
-document.write('<iframe src="https://2507573.fls.doubleclick.net/activityi;src=2507573;type=other026;cat=googl348;ord=' + a + '?" width="1" height="1" frameborder="0" style="display:none"></iframe>');
-</script>
-<noscript>
-<iframe src="https://2507573.fls.doubleclick.net/activityi;src=2507573;type=other026;cat=googl348;ord=1?" width="1" height="1" frameborder="0" style="display:none"></iframe>
-</noscript>
-<!-- End of Tag -->
-</body>
-</html>
-
-
-
diff --git a/docs/html/wear/notifications/remote-input.jd b/docs/html/wear/notifications/remote-input.jd
new file mode 100644
index 0000000..1668363
--- /dev/null
+++ b/docs/html/wear/notifications/remote-input.jd
@@ -0,0 +1,213 @@
+page.title=Receiving Voice Input from a Notification
+
+@jd:body
+
+<img src="{@docRoot}wear/images/13_voicereply.png" height="200" width="169" style="float:right;margin:0 0 20px 40px" />
+
+<img src="{@docRoot}wear/images/03_actions.png" height="200" width="169" style="float:right;margin:0 0 20px 40px" />
+
+<p>If your notification includes an action to respond with text,
+    such as to reply to an email, it should normally launch an activity
+    on the handheld device. However, when your notification appears on an Android wearable, you can
+    allow users to dictate a reply with voice input. You can also provide pre-defined text
+    messages for the user to select.</p>
+
+<p>When the user replies with voice or selects one of the available
+messages, the system sends the message to your app on the connected handheld device.
+The message is attached as an extra in the {@link android.content.Intent} you specified
+to be used for the notification action.</p>
+
+<p class="note"><strong>Note:</strong> When developing with the Android emulator,
+you must type text replies into the voice input field, so be sure you have enabled
+<strong>Hardware keyboard present</strong> in the AVD settings.</p>
+
+
+<h2 id="RemoteInput">Define the Remote Input</h2>
+
+<p>To create an action that supports voice input, first create an instance of
+  <a href="{@docRoot}reference/android/preview/support/wearable/notifications/RemoteInput.html">
+<code>RemoteInput</code></a> using the
+  <a href="{@docRoot}reference/android/preview/support/wearable/notifications/RemoteInput.Builder.html"><code>RemoteInput.Builder</code></a> APIs.
+    The
+  <a href="{@docRoot}reference/android/preview/support/wearable/notifications/RemoteInput.Builder.html"><code>RemoteInput.Builder</code></a> constructor takes a string that the system
+    will use as a key for the {@link android.content.Intent} extra that carries the reply message
+    to your app on the handheld.</p>
+
+<p>For example, here's how to create a new
+  <a href="{@docRoot}reference/android/preview/support/wearable/notifications/RemoteInput.html">
+<code>RemoteInput</code></a> object that provides a custom
+    label for the voice input prompt:</p>
+
+<pre class="prettyprint">
+// Key for the string that's delivered in the action's intent
+private static final String EXTRA_VOICE_REPLY = "extra_voice_reply";
+
+String replyLabel = getResources().getString(R.string.reply_label);
+
+RemoteInput remoteInput = new RemoteInput.Builder(EXTRA_VOICE_REPLY)
+        .setLabel(replyLabel)
+        .build();
+</pre>
+
+
+<h3>Add Pre-defined Text Responses</h3>
+
+<img src="{@docRoot}wear/images/12_voicereply.png" height="200" style="float:right;margin:0 0 20px 40px" />
+
+<p>In addition to allowing voice input, you can
+    provide up to five text responses that the user can select for quick replies. Call
+  <a href="{@docRoot}reference/android/preview/support/wearable/notifications/RemoteInput.Builder.html#setChoices(java.lang.String[])"><code>setChoices()</code></a> and pass it a string array.</p>
+
+<p>For example, you may define some responses in a resource array:</p>
+
+<p class="code-caption">res/values/strings.xml</code>
+<pre class="prettyprint">
+&lt;?xml version="1.0" encoding="utf-8"?>
+&lt;resources>
+    &lt;string-array name="reply_choices">
+        &lt;item>Yes&lt;/item>
+        &lt;item>No&lt;/item>
+        &lt;item>Maybe&lt;/item>
+    &lt;/string-array>
+&lt;/resources>
+</pre>
+
+<p>Then, inflate the string array and add it to the
+  <a href="{@docRoot}reference/android/preview/support/wearable/notifications/RemoteInput.html"><code>RemoteInput</code></a>:</p>
+
+<pre>
+String replyLabel = getResources().getString(R.string.reply_label);
+String[] replyChoices = getResources().getStringArray(R.array.reply_choices);
+
+RemoteInput remoteInput = new RemoteInput.Builder(EXTRA_VOICE_REPLY)
+        .setLabel(replyLabel)
+        .setChoices(replyChoices)
+        .build();
+</pre>
+
+
+
+
+<h2 id="PrimaryAction">Receive Voice Input for the Primary Action</h2>
+
+<p>If "Reply" is your notification's primary action (defined by the {@link
+android.support.v4.app.NotificationCompat.Builder#setContentIntent setContentIntent()}
+method), then you should attach the
+  <a href="{@docRoot}reference/android/preview/support/wearable/notifications/RemoteInput.html"><code>RemoteInput</code></a> to the main action using
+  <a href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html#addRemoteInputForContentIntent(android.preview.support.wearable.notifications.RemoteInput)">
+<code>addRemoteInputForContentIntent()</code></a>. For example:</p>
+
+<pre>
+// Create intent for reply action
+Intent replyIntent = new Intent(this, ReplyActivity.class);
+PendingIntent replyPendingIntent =
+        PendingIntent.getActivity(this, 0, replyIntent, 0);
+
+// Build the notification
+NotificationCompat.Builder replyNotificationBuilder =
+        new NotificationCompat.Builder(this)
+        .setSmallIcon(R.drawable.ic_new_message)
+        .setContentTitle("Message from Travis")
+        .setContentText("I love key lime pie!")
+        .setContentIntent(replyPendingIntent);
+
+// Create the remote input
+RemoteInput remoteInput = new RemoteInput.Builder(EXTRA_VOICE_REPLY)
+        .setLabel(replyLabel)
+        .build();
+
+// Create wearable notification and add remote input
+Notification replyNotification =
+        new WearableNotifications.Builder(replyNotificationBuilder)
+        .addRemoteInputForContentIntent(remoteInput)
+        .build();
+</pre>
+
+
+<p>By using
+  <a href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html#addRemoteInputForContentIntent(android.preview.support.wearable.notifications.RemoteInput)">
+<code>addRemoteInputForContentIntent()</code></a> to add the
+  <a href="{@docRoot}reference/android/preview/support/wearable/notifications/RemoteInput.html"><code>RemoteInput</code></a> object to the notification's primary action,
+the button that normally appears as an "Open" action becomes the "Reply" action
+and starts the voice input UI when users select it on Android Wear.</p>
+
+
+
+<h2 id="NewAction">Receive Voice Input for a Secondary Action</h2>
+
+<p>If the "Reply" action is not your notification's primary action and you want to enable
+voice input for a secondary action, add the
+  <a href="{@docRoot}reference/android/preview/support/wearable/notifications/RemoteInput.html"><code>RemoteInput</code></a> to a new action button defined by an
+  <a href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.Action.html">
+<code>Action</code></a> object.</p>
+
+<p>You should instantiate the
+  <a href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.Action.html">
+<code>Action</code></a> with the
+  <a href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.Action.Builder.html"><code>Action.Builder()</code></a>
+constructor, which takes an icon and text label for the action button, plus the
+{@link android.app.PendingIntent}
+the system should use to invoke your app when the user selects the action. For example:</p>
+
+<pre>
+// Create the pending intent to fire when the user selects the action
+Intent replyIntent = new Intent(this, ReplyActivity.class);
+PendingIntent pendingReplyIntent =
+        PendingIntent.getActivity(this, 0, replyIntent, 0);
+
+// Create the remote input
+RemoteInput remoteInput = new RemoteInput.Builder(EXTRA_VOICE_REPLY)
+        .setLabel(replyLabel)
+        .build();
+
+// Create the notification action
+Action replyAction = new Action.Builder(R.drawable.ic_message,
+        "Reply", pendingIntent)
+        .addRemoteInput(remoteInput)
+        .build();
+</pre>
+
+
+<p>After you add the
+  <a href="{@docRoot}reference/android/preview/support/wearable/notifications/RemoteInput.html"><code>RemoteInput</code></a> to the
+  <a href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.Action.html">
+<code>Action</code></a>, add the
+  <a href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.Action.html">
+<code>Action</code></a> to the
+  <a href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html"><code>WearableNotifications.Builder</code></a> using
+  <a href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html#addAction(Action)"><code>addAction()</code></a>.
+For example:</p>
+
+<pre>
+// Create basic notification builder
+NotificationCompat.Builder replyNotificationBuilder =
+        new NotificationCompat.Builder(this)
+        .setContentTitle("New message");
+
+// Create the notification action and add remote input
+Action replyAction = new Action.Builder(R.drawable.ic_message,
+        "Reply", pendingIntent)
+        .addRemoteInput(remoteInput)
+        .build();
+
+// Create wearable notification and add action
+Notification replyNotification =
+        new WearableNotifications.Builder(replyNotificationBuilder)
+        .addAction(replyAction)
+        .build();
+</pre>
+
+<p>Now, when the user selects "Reply" from an Android wearable, the system prompts the user
+    for voice input (and shows the list of pre-defined replies, if provided).
+    Once the user completes a response, the system invokes
+    the {@link android.content.Intent} attached to the action and adds the
+<code>EXTRA_VOICE_REPLY</code> extra (the string
+    you passed to the
+  <a href="{@docRoot}reference/android/preview/support/wearable/notifications/RemoteInput.Builder.html"><code>RemoteInput.Builder</code></a> constructor)
+    with the user's message as the string value.</p>
+
+
+
+
+</body>
+</html>
diff --git a/docs/html/wear/notifications/stacks.html b/docs/html/wear/notifications/stacks.html
deleted file mode 100644
index e4f74a0..0000000
--- a/docs/html/wear/notifications/stacks.html
+++ /dev/null
@@ -1,512 +0,0 @@
-<!DOCTYPE html>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-<html>
-<head>
-
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
-<meta name="viewport" content="width=device-width" />
-
-<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
-<title>Stacking Notifications | Android Developers</title>
-
-<!-- STYLESHEETS -->
-<link rel="stylesheet"
-href="//fonts.googleapis.com/css?family=Roboto:light,regular,medium,thin,italic,mediumitalic,bold" title="roboto">
-<link href="/assets/css/default.css" rel="stylesheet" type="text/css">
-
-
-
-<!-- JAVASCRIPT -->
-<script src="//www.google.com/jsapi" type="text/javascript"></script>
-<script src="/assets/js/android_3p-bundle.js" type="text/javascript"></script>
-<script type="text/javascript">
-  var toRoot = "/";
-  var metaTags = [];
-  var devsite = false;
-</script>
-<script src="/assets/js/docs.js" type="text/javascript"></script>
-
-<script type="text/javascript">
-  var _gaq = _gaq || [];
-  _gaq.push(['_setAccount', 'UA-5831155-1']);
-  _gaq.push(['_trackPageview']);
-
-  (function() {
-    var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
-    ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
-    var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
-  })();
-</script>
-</head>
-
-<body class="gc-documentation 
-  " itemscope itemtype="http://schema.org/Article">
-
-
-  
-<a name="top"></a>
-
-    <!-- Header -->
-    <div id="header">
-        <div class="wrap" id="header-wrap">
-          <div class="col-3 logo-wear">
-          <a href="/wear/index.html">
-            <img src="/wear/images/android-wear.png" height="16" alt="Android Wear" />
-          </a>
-          </div>
-
-
-	<div class="col-8" style="margin:0"><h1 style="margin:1px 0 0 20px;padding:0;line-height:16px;
-  color:#666;font-weight:100;font-size:24px;">Developer Preview</h1></div>
-            
-
-          <!-- New Search -->
-          <div class="menu-container">
-            <div class="moremenu">
-	        <div id="more-btn"></div>
-	    </div>
-  <div class="morehover" id="moremenu">
-    <div class="top"></div>
-    <div class="mid">
-      <div class="header">Links</div>
-      <ul>
-        <li><a href="https://play.google.com/apps/publish/">Google Play Developer Console</a></li>
-        <li><a href="http://android-developers.blogspot.com/">Android Developers Blog</a></li>
-        <li><a href="/about/index.html">About Android</a></li>
-      </ul>
-      <div class="header">Android Sites</div>
-      <ul>
-        <li><a href="http://www.android.com">Android.com</a></li>
-        <li class="active"><a>Android Developers</a></li>
-        <li><a href="http://source.android.com">Android Open Source Project</a></li>
-      </ul>
-      
-      
-      
-        <div class="header">Language</div>
-          <div id="language" class="locales">
-            <select name="language" onChange="changeLangPref(this.value, true)">
-                <option value="en">English</option>
-                <option value="es">Español</option>
-                <option value="ja">日本語</option>
-                <option value="ko">한국어</option>
-                <option value="ru">Русский</option>
-                <option value="zh-cn">中文 (中国)</option>
-                <option value="zh-tw">中文 (台灣)</option>
-            </select>
-          </div>
-        <script type="text/javascript">
-          <!--
-          loadLangPref();
-            //-->
-        </script>
-      
-      
-
-
-      <br class="clearfix" />
-    </div><!-- end mid -->
-    <div class="bottom"></div>
-  </div><!-- end morehover -->
-
-  <div class="search" id="search-container">
-    <div class="search-inner">
-      <div id="search-btn"></div>
-      <div class="left"></div>
-      <form onsubmit="return submit_search()">
-        <input id="search_autocomplete" type="text" value="" autocomplete="off" name="q"
-onfocus="search_focus_changed(this, true)" onblur="search_focus_changed(this, false)"
-onkeydown="return search_changed(event, true, '/')" 
-onkeyup="return search_changed(event, false, '/')" />
-      </form>
-      <div class="right"></div>
-        <a class="close hide">close</a>
-        <div class="left"></div>
-        <div class="right"></div>
-    </div>
-  </div><!--  end search -->
-
-  <div class="search_filtered_wrapper reference">
-    <div class="suggest-card reference no-display">
-      <ul class="search_filtered">
-      </ul>
-    </div>
-  </div>
-
-  <div class="search_filtered_wrapper docs">
-    <div class="suggest-card dummy no-display">&nbsp;</div>
-    <div class="suggest-card develop no-display">
-      <ul class="search_filtered">
-      </ul>
-      <div class="child-card guides no-display">
-      </div>
-      <div class="child-card training no-display">
-      </div>
-      <div class="child-card samples no-display">
-      </div>
-    </div>
-    <div class="suggest-card design no-display">
-      <ul class="search_filtered">
-      </ul>
-    </div>
-    <div class="suggest-card distribute no-display">
-      <ul class="search_filtered">
-      </ul>
-    </div>
-  </div><!-- end search_filtered_wrapper -->
-
-  </div>
-  <!-- end menu_container -->
-
-
-        </div><!-- end header-wrap -->
-    </div>
-    <!-- /Header -->
-
-
-  <div id="searchResults" class="wrap" style="display:none;">
-          <h2 id="searchTitle">Results</h2>
-          <div id="leftSearchControl" class="search-control">Loading...</div>
-  </div>
-
-  
-
-  
-
-  <div class="wrap clearfix" id="body-content">
-    <div class="col-4" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
-      <div id="devdoc-nav" class="scroll-pane">
-<a class="totop" href="#top" data-g-event="left-nav-top">to top</a>
-
-<ul id="nav">
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/wear/preview/start.html">Get Started
-      </a></div>
-  </li>
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/wear/design/user-interface.html">UI Overview
-      </a></div>
-  </li>
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/wear/design/index.html">Design Principles
-      </a></div>
-  </li>
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/wear/notifications/creating.html">Creating Notifications for Android Wear
-      </a></div>
-  </li>
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/wear/notifications/remote-input.html">Receiving Voice Input from a Notification
-      </a></div>
-  </li>
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/wear/notifications/pages.html">Adding Pages to a Notification
-      </a></div>
-  </li>
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/wear/notifications/stacks.html">Stacking Notifications
-      </a></div>
-  </li>
-
-  <li class="nav-section">
-    <div class="nav-section-header"><a href="/reference/android/preview/support/package-summary.html">Notification Reference</a></div>
-    <ul class="tree-list-children">
-<li class="nav-section">
-<div class="nav-section-header-ref"><span class="tree-list-subtitle package" title="android.preview.support.v4.app">android.preview.support.v4.app</span></div>
-  <ul>
-<li><a href="/reference/android/preview/support/v4/app/NotificationManagerCompat.html">NotificationManagerCompat</a></li>
-  </ul>
-</li>
-
-<li class="nav-section">
-<div class="nav-section-header-ref"><span class="tree-list-subtitle package" title="android.preview.support.wearable.notifications">android.preview.support.wearable.notifications</span></div>
-<ul>
-
-<li><a href="/reference/android/preview/support/wearable/notifications/RemoteInput.html">RemoteInput</a></li>
-<li><a href="/reference/android/preview/support/wearable/notifications/RemoteInput.Builder.html" >RemoteInput.Builder</a></li>
-
-<li><a href="/reference/android/preview/support/wearable/notifications/WearableNotifications.html">WearableNotifications</a></li>
-
-<li><a href="/reference/android/preview/support/wearable/notifications/WearableNotifications.Action.html">WearableNotifications.Action</a></li>
-
-<li><a href="/reference/android/preview/support/wearable/notifications/WearableNotifications.Action.Builder.html">WearableNotifications.Action.Builder</a></li>
-
-<li><a href="/reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html">WearableNotifications.Builder</a></li>
-	</ul>
-  </li>
-</ul>
-</li>
-
-
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/wear/license.html">License Agreement</a></div>
-  </li>
-
-
-</ul>
-
-        
-
-      </div>
-    </div> <!-- end side-nav -->
-    <script>
-      $(document).ready(function() {
-        scrollIntoView("devdoc-nav");
-        });
-    </script>
-
-
-
-
-<div class="col-12" id="doc-col" >
-
-
-  
-    
-      
-        <h1 itemprop="name" >Stacking Notifications</h1>
-      
-    
-  
-
-
-  
-  <div id="jd-content">
-
-
-    <div class="jd-descr" itemprop="articleBody">
-    <img src="/wear/images/11_bundles_B.png" height="200" width="169" style="float:right;margin:0 0 20px 40px" />
-<img src="/wear/images/11_bundles_A.png" height="200" width="169" style="float:right;margin:0 0 20px 40px" />
-
-<p>When creating notifications for a handheld device, you should always aggregate similar
-notifications into a single summary notification. For example, if your app creates notifications
-for received messages, you should not show more than one notification
-on a handheld device&mdash;when more than one is message is received, use a single notification
-to provide a summary such as "2 new messages."</p>
-
-<p>However, a summary notification is less useful on an Android wearable because users
-are not able to read details from each message on the wearable (they must open your app on the
-handheld to view more information). So for the wearable device, you should
-group all the notifications together in a stack. The stack of notifications appears as a single
-card, which users can expand to view the details from each notification separately. The new
-<a href="/reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html#setGroup(java.lang.String, int)">
-<code>setGroup()</code></a> method makes this possible while allowing you to still provide
-only one summary notification on the handheld device.</p>
-
-<p>For details about designing notification stacks, see the
-<a href="/wear/design/index.html#NotificationStacks">Design Principles of Android
-Wear</a>.</p>
-
-
-<h2 id="AddGroup">Add Each Notification to a Group</h2>
-
-<p>To create a stack, call <a
-href="/reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html#setGroup(java.lang.String, int)">
-<code>setGroup()</code></a> for each notification you want in the stack, passing the same
-group key. For example:</p>
-
-<pre style="clear:right">
-final static String GROUP_KEY_EMAILS = "group_key_emails";
-
-NotificationCompat.Builder builder = new NotificationCompat.Builder(mContext)
-         .setContentTitle("New mail from " + sender)
-         .setContentText(subject)
-         .setSmallIcon(R.drawable.new_mail);
-
-Notification notif = new WearableNotifications.Builder(builder)
-         .setGroup(GROUP_KEY_EMAILS)
-         .build();
-</pre>
-
-<p>By default, notifications appear in the order in which you added them, with the most recent
-  notification visible at the top.  You can define a specific position in the group
-  by passing an order position as the second parameter for <a
-href="/reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html#setGroup(java.lang.String, int)">
-<code>setGroup()</code></a>.</p>
-
-
-<h2 id="AddSummary">Add a Summary Notification</h2>
-
-<p>It's important that you still provide a summary notification that appears on handheld devices.
-So in addition to adding each unique notification to the same stack group, also add a summary
-notification, but set its order position to be <a
-href="/reference/android/preview/support/wearable/notifications/WearableNotifications.html#GROUP_ORDER_SUMMARY"><code>GROUP_ORDER_SUMMARY</code></a>.</p>
-
-<pre>
-Notification summaryNotification = new WearableNotifications.Builder(builder)
-         .setGroup(GROUP_KEY_EMAILS, WearableNotifications.GROUP_ORDER_SUMMARY)
-         .build();
-</pre>
-
-<p>This notification will not appear in your stack of notifications on the wearable, but
-appears as the only notification on the handheld device.
-
-</body>
-</html>
-
-    </div>
-
-      <div class="content-footer layout-content-row"
-                    itemscope itemtype="http://schema.org/SiteNavigationElement">
-        <div class="layout-content-col col-9" style="padding-top:4px">
-          
-            <div class="g-plusone" data-size="medium"></div>
-          
-        </div>
-        
-        <div class="paging-links layout-content-col col-4">
-          
-        </div>
-        
-      </div>
-
-      
-      
-
-  </div> <!-- end jd-content -->
-
-<div id="footer" class="wrap" >
-        
-
-  <div id="copyright">
-    
-  Except as noted, this content is 
-  licensed under <a href="http://creativecommons.org/licenses/by/2.5/">
-  Creative Commons Attribution 2.5</a>. For details and 
-  restrictions, see the <a href="/license.html">Content 
-  License</a>.
-  </div>
-
-
-  <div id="footerlinks">
-    
-  <p>
-    <a href="/about/index.html">About Android</a>&nbsp;&nbsp;|&nbsp;
-    <a href="/legal.html">Legal</a>&nbsp;&nbsp;|&nbsp;
-    <a href="/support.html">Support</a>
-  </p>
-  </div>
-
-</div> <!-- end footer -->
-</div><!-- end doc-content -->
-
-</div> <!-- end body-content --> 
-
-
-
-
-
-
-<!-- Start of Tag -->
-<script type="text/javascript">
-var axel = Math.random() + "";
-var a = axel * 10000000000000;
-document.write('<iframe src="https://2507573.fls.doubleclick.net/activityi;src=2507573;type=other026;cat=googl348;ord=' + a + '?" width="1" height="1" frameborder="0" style="display:none"></iframe>');
-</script>
-<noscript>
-<iframe src="https://2507573.fls.doubleclick.net/activityi;src=2507573;type=other026;cat=googl348;ord=1?" width="1" height="1" frameborder="0" style="display:none"></iframe>
-</noscript>
-<!-- End of Tag -->
-</body>
-</html>
-
-
-
diff --git a/docs/html/wear/notifications/stacks.jd b/docs/html/wear/notifications/stacks.jd
new file mode 100644
index 0000000..a2d34ce
--- /dev/null
+++ b/docs/html/wear/notifications/stacks.jd
@@ -0,0 +1,132 @@
+page.title=Stacking Notifications
+
+@jd:body
+
+<img src="{@docRoot}wear/images/11_bundles_B.png" height="200" width="169" style="float:right;margin:0 0 20px 40px" alt="" />
+<img src="{@docRoot}wear/images/11_bundles_A.png" height="200" width="169" style="float:right;margin:0 0 20px 40px" alt="" />
+
+<p>When creating notifications for a handheld device, you should always aggregate similar
+notifications into a single summary notification. For example, if your app creates notifications
+for received messages, you should not show more than one notification
+on a handheld device&mdash;when more than one is message is received, use a single notification
+to provide a summary such as "2 new messages."</p>
+
+<p>However, a summary notification is less useful on an Android wearable because users
+are not able to read details from each message on the wearable (they must open your app on the
+handheld to view more information). So for the wearable device, you should
+group all the notifications together in a stack. The stack of notifications appears as a single
+card, which users can expand to view the details from each notification separately. The new
+<a href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html#setGroup(java.lang.String, int)">
+<code>setGroup()</code></a> method makes this possible while allowing you to still provide
+only one summary notification on the handheld device.</p>
+
+<p>For details about designing notification stacks, see the
+<a href="{@docRoot}wear/design/index.html#NotificationStacks">Design Principles of Android
+Wear</a>.</p>
+
+
+<h2 id="AddGroup">Add Each Notification to a Group</h2>
+
+<p>To create a stack, call <a
+href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html#setGroup(java.lang.String, int)">
+<code>setGroup()</code></a> for each notification you want in the stack and specify a
+group key. Then call <a href="{@docRoot}reference/android/preview/support/v4/app/NotificationManagerCompat.html#notify(int, android.app.Notification)"><code>notify()</code></a> to send it to the wearable.</p>
+
+<pre style="clear:right">
+final static String GROUP_KEY_EMAILS = "group_key_emails";
+
+// Build the notification and pass this builder to WearableNotifications.Builder
+NotificationCompat.Builder builder = new NotificationCompat.Builder(mContext)
+         .setContentTitle("New mail from " + sender1)
+         .setContentText(subject1)
+         .setSmallIcon(R.drawable.new_mail);
+
+Notification notif1 = new WearableNotifications.Builder(builder)
+         .setGroup(GROUP_KEY_EMAILS)
+         .build();
+
+// Issue the notification
+NotificationManagerCompat notificationManager =
+        NotificationManagerCompat.from(this);
+notificationManager.notify(notificationId1, notif);
+</pre>
+
+<p>Later on, when you create another notification, specify
+the same group key. When you call <a href="{@docRoot}reference/android/preview/support/v4/app/NotificationManagerCompat.html#notify(int, android.app.Notification)"><code>notify()</code></a>, this notification appears
+in the same stack as the previous notification, instead of as a new card:</p>
+
+<pre style="clear:right">
+builder = new NotificationCompat.Builder(mContext)
+         .setContentTitle("New mail from " + sender2)
+         .setContentText(subject2)
+         .setSmallIcon(R.drawable.new_mail);
+
+// Use the same group as the previous notification
+Notification notif2 = new WearableNotifications.Builder(builder)
+         .setGroup(GROUP_KEY_EMAILS)
+         .build();
+
+notificationManager.notify(notificationId2, notif);
+</pre>
+
+<p>By default, notifications appear in the order in which you added them, with the most recent
+  notification visible at the top.  You can define a specific position in the group
+  by passing an order position as the second parameter for <a
+href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html#setGroup(java.lang.String, int)">
+<code>setGroup()</code></a>.</p>
+
+
+<h2 id="AddSummary">Add a Summary Notification</h2>
+
+<img src="{@docRoot}wear/images/notif_summary_framed.png" height="242" width="330" style="float:right;margin:0 0 20px 40px" alt="" />
+
+<p>It's important that you still provide a summary notification that appears on handheld devices.
+So in addition to adding each unique notification to the same stack group, also add a summary
+notification, but set its order position to be <a
+href="{@docRoot}reference/android/preview/support/wearable/notifications/WearableNotifications.html#GROUP_ORDER_SUMMARY"><code>GROUP_ORDER_SUMMARY</code></a>.</p>
+
+<p>This notification does not appear in your stack of notifications on the wearable, but
+appears as the only notification on the handheld device.</p>
+
+<pre style="clear:right">
+Bitmap largeIcon = BitmapFactory.decodeResource(getResources(),
+        R.drawable.ic_large_icon);
+
+builder = new NotificationCompat.Builder(this)
+        .setSmallIcon(R.drawable.ic_small_icon)
+        .setLargeIcon(largeIcon);
+
+// Use the same group key and pass this builder to InboxStyle notification
+WearableNotifications.Builder wearableBuilder = new WearableNotifications
+        .Builder(builder)
+        .setGroup(GROUP_KEY_EMAILS,
+                WearableNotifications.GROUP_ORDER_SUMMARY);
+
+// Build the final notification to show on the handset
+Notification summaryNotification = new NotificationCompat.InboxStyle(
+        wearableBuilder.getCompatBuilder())
+        .addLine("Alex Faaborg   Check this out")
+        .addLine("Jeff Chang   Launch Party")
+        .setBigContentTitle("2 new messages")
+        .setSummaryText("johndoe@gmail.com")
+        .build();
+
+notificationManager.notify(notificationId3, summaryNotification);
+</pre>
+
+<p>
+This notification uses {@link android.support.v4.app.NotificationCompat.InboxStyle},
+which gives you an easy way to create notifications for email or messaging apps.
+You can use this style, another one defined in {@link android.support.v4.app.NotificationCompat},
+or no style for the summary notification.
+</p>
+
+<p class="note"><b>Tip:</b>
+To style the text like in the example screenshot, see
+<a href="{@docRoot}guide/topics/resources/string-resource.html#StylingWithHTML">Styling
+with HTML markup</a> and
+<a href="{@docRoot}guide/topics/resources/string-resource.html#StylingWithSpannables">Styling
+with Spannables</a>.
+</p>
+</body>
+</html>
\ No newline at end of file
diff --git a/docs/html/wear/preview/signup.html b/docs/html/wear/preview/signup.jd
similarity index 64%
rename from docs/html/wear/preview/signup.html
rename to docs/html/wear/preview/signup.jd
index ca50179..8e8ec9a 100644
--- a/docs/html/wear/preview/signup.html
+++ b/docs/html/wear/preview/signup.jd
@@ -1,379 +1,8 @@
-<!DOCTYPE html>
+page.title=Sign Up for the Developer Preview
 
+@jd:body
 
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-<html>
-<head>
-
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
-<meta name="viewport" content="width=device-width" />
-
-<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
-<title>Sign Up for the Developer Preview | Android Developers</title>
-
-<!-- STYLESHEETS -->
-<link rel="stylesheet"
-href="//fonts.googleapis.com/css?family=Roboto:light,regular,medium,thin,italic,mediumitalic,bold" title="roboto">
-<link href="/assets/css/default.css" rel="stylesheet" type="text/css">
-
-
-
-<!-- JAVASCRIPT -->
-<script src="//www.google.com/jsapi" type="text/javascript"></script>
-<script src="/assets/js/android_3p-bundle.js" type="text/javascript"></script>
-<script type="text/javascript">
-  var toRoot = "/";
-  var metaTags = [];
-  var devsite = false;
-</script>
-<script src="/assets/js/docs.js" type="text/javascript"></script>
-
-<script type="text/javascript">
-  var _gaq = _gaq || [];
-  _gaq.push(['_setAccount', 'UA-5831155-1']);
-  _gaq.push(['_trackPageview']);
-
-  (function() {
-    var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
-    ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
-    var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
-  })();
-</script>
-</head>
-
-<body class="gc-documentation 
-  " itemscope itemtype="http://schema.org/Article">
-
-
-  
-<a name="top"></a>
-
-    <!-- Header -->
-    <div id="header">
-        <div class="wrap" id="header-wrap">
-          <div class="col-3 logo-wear">
-          <a href="/wear/index.html">
-            <img src="/wear/images/android-wear.png" height="16" alt="Android Wear" />
-          </a>
-          </div>
-
-
-	<div class="col-8" style="margin:0"><h1 style="margin:1px 0 0 20px;padding:0;line-height:16px;
-  color:#666;font-weight:100;font-size:24px;">Developer Preview</h1></div>
-            
-
-          <!-- New Search -->
-          <div class="menu-container">
-            <div class="moremenu">
-	        <div id="more-btn"></div>
-	    </div>
-  <div class="morehover" id="moremenu">
-    <div class="top"></div>
-    <div class="mid">
-      <div class="header">Links</div>
-      <ul>
-        <li><a href="https://play.google.com/apps/publish/">Google Play Developer Console</a></li>
-        <li><a href="http://android-developers.blogspot.com/">Android Developers Blog</a></li>
-        <li><a href="/about/index.html">About Android</a></li>
-      </ul>
-      <div class="header">Android Sites</div>
-      <ul>
-        <li><a href="http://www.android.com">Android.com</a></li>
-        <li class="active"><a>Android Developers</a></li>
-        <li><a href="http://source.android.com">Android Open Source Project</a></li>
-      </ul>
-      
-      
-      
-        <div class="header">Language</div>
-          <div id="language" class="locales">
-            <select name="language" onChange="changeLangPref(this.value, true)">
-                <option value="en">English</option>
-                <option value="es">Español</option>
-                <option value="ja">日本語</option>
-                <option value="ko">한국어</option>
-                <option value="ru">Русский</option>
-                <option value="zh-cn">中文 (中国)</option>
-                <option value="zh-tw">中文 (台灣)</option>
-            </select>
-          </div>
-        <script type="text/javascript">
-          <!--
-          loadLangPref();
-            //-->
-        </script>
-      
-      
-
-
-      <br class="clearfix" />
-    </div><!-- end mid -->
-    <div class="bottom"></div>
-  </div><!-- end morehover -->
-
-  <div class="search" id="search-container">
-    <div class="search-inner">
-      <div id="search-btn"></div>
-      <div class="left"></div>
-      <form onsubmit="return submit_search()">
-        <input id="search_autocomplete" type="text" value="" autocomplete="off" name="q"
-onfocus="search_focus_changed(this, true)" onblur="search_focus_changed(this, false)"
-onkeydown="return search_changed(event, true, '/')" 
-onkeyup="return search_changed(event, false, '/')" />
-      </form>
-      <div class="right"></div>
-        <a class="close hide">close</a>
-        <div class="left"></div>
-        <div class="right"></div>
-    </div>
-  </div><!--  end search -->
-
-  <div class="search_filtered_wrapper reference">
-    <div class="suggest-card reference no-display">
-      <ul class="search_filtered">
-      </ul>
-    </div>
-  </div>
-
-  <div class="search_filtered_wrapper docs">
-    <div class="suggest-card dummy no-display">&nbsp;</div>
-    <div class="suggest-card develop no-display">
-      <ul class="search_filtered">
-      </ul>
-      <div class="child-card guides no-display">
-      </div>
-      <div class="child-card training no-display">
-      </div>
-      <div class="child-card samples no-display">
-      </div>
-    </div>
-    <div class="suggest-card design no-display">
-      <ul class="search_filtered">
-      </ul>
-    </div>
-    <div class="suggest-card distribute no-display">
-      <ul class="search_filtered">
-      </ul>
-    </div>
-  </div><!-- end search_filtered_wrapper -->
-
-  </div>
-  <!-- end menu_container -->
-
-
-        </div><!-- end header-wrap -->
-    </div>
-    <!-- /Header -->
-
-
-  <div id="searchResults" class="wrap" style="display:none;">
-          <h2 id="searchTitle">Results</h2>
-          <div id="leftSearchControl" class="search-control">Loading...</div>
-  </div>
-
-  
-
-  
-
-  <div class="wrap clearfix" id="body-content">
-    <div class="col-4" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
-      <div id="devdoc-nav" class="scroll-pane">
-<a class="totop" href="#top" data-g-event="left-nav-top">to top</a>
-
-<ul id="nav">
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/wear/preview/start.html">Get Started
-      </a></div>
-  </li>
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/wear/design/user-interface.html">UI Overview
-      </a></div>
-  </li>
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/wear/design/index.html">Design Principles
-      </a></div>
-  </li>
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/wear/notifications/creating.html">Creating Notifications for Android Wear
-      </a></div>
-  </li>
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/wear/notifications/remote-input.html">Receiving Voice Input from a Notification
-      </a></div>
-  </li>
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/wear/notifications/pages.html">Adding Pages to a Notification
-      </a></div>
-  </li>
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/wear/notifications/stacks.html">Stacking Notifications
-      </a></div>
-  </li>
-
-  <li class="nav-section">
-    <div class="nav-section-header"><a href="/reference/android/preview/support/package-summary.html">Notification Reference</a></div>
-    <ul class="tree-list-children">
-<li class="nav-section">
-<div class="nav-section-header-ref"><span class="tree-list-subtitle package" title="android.preview.support.v4.app">android.preview.support.v4.app</span></div>
-  <ul>
-<li><a href="/reference/android/preview/support/v4/app/NotificationManagerCompat.html">NotificationManagerCompat</a></li>
-  </ul>
-</li>
-
-<li class="nav-section">
-<div class="nav-section-header-ref"><span class="tree-list-subtitle package" title="android.preview.support.wearable.notifications">android.preview.support.wearable.notifications</span></div>
-<ul>
-
-<li><a href="/reference/android/preview/support/wearable/notifications/RemoteInput.html">RemoteInput</a></li>
-<li><a href="/reference/android/preview/support/wearable/notifications/RemoteInput.Builder.html" >RemoteInput.Builder</a></li>
-
-<li><a href="/reference/android/preview/support/wearable/notifications/WearableNotifications.html">WearableNotifications</a></li>
-
-<li><a href="/reference/android/preview/support/wearable/notifications/WearableNotifications.Action.html">WearableNotifications.Action</a></li>
-
-<li><a href="/reference/android/preview/support/wearable/notifications/WearableNotifications.Action.Builder.html">WearableNotifications.Action.Builder</a></li>
-
-<li><a href="/reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html">WearableNotifications.Builder</a></li>
-	</ul>
-  </li>
-</ul>
-</li>
-
-
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/wear/license.html">License Agreement</a></div>
-  </li>
-
-
-</ul>
-
-        
-
-      </div>
-    </div> <!-- end side-nav -->
-    <script>
-      $(document).ready(function() {
-        scrollIntoView("devdoc-nav");
-        });
-    </script>
-
-
-
-
-<div class="col-12" id="doc-col" >
-
-
-  
-    
-      
-        <h1 itemprop="name" >Sign Up for the Developer Preview</h1>
-      
-    
-  
-
-
-  
-  <div id="jd-content">
-
-
-    <div class="jd-descr" itemprop="articleBody">
-    <p>To get started with the Android Wear Developer Preview, you must agree to the
+<p>To get started with the Android Wear Developer Preview, you must agree to the
   following terms and conditions and provide the email address for your Google account.
 After signing up, you’ll have access to:</p>
 <ul>
@@ -538,72 +167,3 @@
 
 </body>
 </html>
-
-    </div>
-
-      <div class="content-footer layout-content-row"
-                    itemscope itemtype="http://schema.org/SiteNavigationElement">
-        <div class="layout-content-col col-9" style="padding-top:4px">
-          
-            <div class="g-plusone" data-size="medium"></div>
-          
-        </div>
-        
-        <div class="paging-links layout-content-col col-4">
-          
-        </div>
-        
-      </div>
-
-      
-      
-
-  </div> <!-- end jd-content -->
-
-<div id="footer" class="wrap" >
-        
-
-  <div id="copyright">
-    
-  Except as noted, this content is 
-  licensed under <a href="http://creativecommons.org/licenses/by/2.5/">
-  Creative Commons Attribution 2.5</a>. For details and 
-  restrictions, see the <a href="/license.html">Content 
-  License</a>.
-  </div>
-
-
-  <div id="footerlinks">
-    
-  <p>
-    <a href="/about/index.html">About Android</a>&nbsp;&nbsp;|&nbsp;
-    <a href="/legal.html">Legal</a>&nbsp;&nbsp;|&nbsp;
-    <a href="/support.html">Support</a>
-  </p>
-  </div>
-
-</div> <!-- end footer -->
-</div><!-- end doc-content -->
-
-</div> <!-- end body-content --> 
-
-
-
-
-
-
-<!-- Start of Tag -->
-<script type="text/javascript">
-var axel = Math.random() + "";
-var a = axel * 10000000000000;
-document.write('<iframe src="https://2507573.fls.doubleclick.net/activityi;src=2507573;type=other026;cat=googl348;ord=' + a + '?" width="1" height="1" frameborder="0" style="display:none"></iframe>');
-</script>
-<noscript>
-<iframe src="https://2507573.fls.doubleclick.net/activityi;src=2507573;type=other026;cat=googl348;ord=1?" width="1" height="1" frameborder="0" style="display:none"></iframe>
-</noscript>
-<!-- End of Tag -->
-</body>
-</html>
-
-
-
diff --git a/docs/html/wear/preview/start.html b/docs/html/wear/preview/start.html
deleted file mode 100644
index b1861f5..0000000
--- a/docs/html/wear/preview/start.html
+++ /dev/null
@@ -1,693 +0,0 @@
-<!DOCTYPE html>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-<html>
-<head>
-
-
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
-<meta name="viewport" content="width=device-width" />
-
-<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
-<title>Get Started with the Developer Preview | Android Developers</title>
-
-<!-- STYLESHEETS -->
-<link rel="stylesheet"
-href="//fonts.googleapis.com/css?family=Roboto:light,regular,medium,thin,italic,mediumitalic,bold" title="roboto">
-<link href="/assets/css/default.css" rel="stylesheet" type="text/css">
-
-
-
-<!-- JAVASCRIPT -->
-<script src="//www.google.com/jsapi" type="text/javascript"></script>
-<script src="/assets/js/android_3p-bundle.js" type="text/javascript"></script>
-<script type="text/javascript">
-  var toRoot = "/";
-  var metaTags = [];
-  var devsite = false;
-</script>
-<script src="/assets/js/docs.js" type="text/javascript"></script>
-
-<script type="text/javascript">
-  var _gaq = _gaq || [];
-  _gaq.push(['_setAccount', 'UA-5831155-1']);
-  _gaq.push(['_trackPageview']);
-
-  (function() {
-    var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
-    ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
-    var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
-  })();
-</script>
-</head>
-
-<body class="gc-documentation 
-  " itemscope itemtype="http://schema.org/Article">
-
-
-  
-<a name="top"></a>
-
-    <!-- Header -->
-    <div id="header">
-        <div class="wrap" id="header-wrap">
-          <div class="col-3 logo-wear">
-          <a href="/wear/index.html">
-            <img src="/wear/images/android-wear.png" height="16" alt="Android Wear" />
-          </a>
-          </div>
-
-
-	<div class="col-8" style="margin:0"><h1 style="margin:1px 0 0 20px;padding:0;line-height:16px;
-  color:#666;font-weight:100;font-size:24px;">Developer Preview</h1></div>
-            
-
-          <!-- New Search -->
-          <div class="menu-container">
-            <div class="moremenu">
-	        <div id="more-btn"></div>
-	    </div>
-  <div class="morehover" id="moremenu">
-    <div class="top"></div>
-    <div class="mid">
-      <div class="header">Links</div>
-      <ul>
-        <li><a href="https://play.google.com/apps/publish/">Google Play Developer Console</a></li>
-        <li><a href="http://android-developers.blogspot.com/">Android Developers Blog</a></li>
-        <li><a href="/about/index.html">About Android</a></li>
-      </ul>
-      <div class="header">Android Sites</div>
-      <ul>
-        <li><a href="http://www.android.com">Android.com</a></li>
-        <li class="active"><a>Android Developers</a></li>
-        <li><a href="http://source.android.com">Android Open Source Project</a></li>
-      </ul>
-      
-      
-      
-        <div class="header">Language</div>
-          <div id="language" class="locales">
-            <select name="language" onChange="changeLangPref(this.value, true)">
-                <option value="en">English</option>
-                <option value="es">Español</option>
-                <option value="ja">日本語</option>
-                <option value="ko">한국어</option>
-                <option value="ru">Русский</option>
-                <option value="zh-cn">中文 (中国)</option>
-                <option value="zh-tw">中文 (台灣)</option>
-            </select>
-          </div>
-        <script type="text/javascript">
-          <!--
-          loadLangPref();
-            //-->
-        </script>
-      
-      
-
-
-      <br class="clearfix" />
-    </div><!-- end mid -->
-    <div class="bottom"></div>
-  </div><!-- end morehover -->
-
-  <div class="search" id="search-container">
-    <div class="search-inner">
-      <div id="search-btn"></div>
-      <div class="left"></div>
-      <form onsubmit="return submit_search()">
-        <input id="search_autocomplete" type="text" value="" autocomplete="off" name="q"
-onfocus="search_focus_changed(this, true)" onblur="search_focus_changed(this, false)"
-onkeydown="return search_changed(event, true, '/')" 
-onkeyup="return search_changed(event, false, '/')" />
-      </form>
-      <div class="right"></div>
-        <a class="close hide">close</a>
-        <div class="left"></div>
-        <div class="right"></div>
-    </div>
-  </div><!--  end search -->
-
-  <div class="search_filtered_wrapper reference">
-    <div class="suggest-card reference no-display">
-      <ul class="search_filtered">
-      </ul>
-    </div>
-  </div>
-
-  <div class="search_filtered_wrapper docs">
-    <div class="suggest-card dummy no-display">&nbsp;</div>
-    <div class="suggest-card develop no-display">
-      <ul class="search_filtered">
-      </ul>
-      <div class="child-card guides no-display">
-      </div>
-      <div class="child-card training no-display">
-      </div>
-      <div class="child-card samples no-display">
-      </div>
-    </div>
-    <div class="suggest-card design no-display">
-      <ul class="search_filtered">
-      </ul>
-    </div>
-    <div class="suggest-card distribute no-display">
-      <ul class="search_filtered">
-      </ul>
-    </div>
-  </div><!-- end search_filtered_wrapper -->
-
-  </div>
-  <!-- end menu_container -->
-
-
-        </div><!-- end header-wrap -->
-    </div>
-    <!-- /Header -->
-
-
-  <div id="searchResults" class="wrap" style="display:none;">
-          <h2 id="searchTitle">Results</h2>
-          <div id="leftSearchControl" class="search-control">Loading...</div>
-  </div>
-
-  
-
-  
-
-  <div class="wrap clearfix" id="body-content">
-    <div class="col-4" id="side-nav" itemscope itemtype="http://schema.org/SiteNavigationElement">
-      <div id="devdoc-nav" class="scroll-pane">
-<a class="totop" href="#top" data-g-event="left-nav-top">to top</a>
-
-<ul id="nav">
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/wear/preview/start.html">Get Started
-      </a></div>
-  </li>
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/wear/design/user-interface.html">UI Overview
-      </a></div>
-  </li>
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/wear/design/index.html">Design Principles
-      </a></div>
-  </li>
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/wear/notifications/creating.html">Creating Notifications for Android Wear
-      </a></div>
-  </li>
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/wear/notifications/remote-input.html">Receiving Voice Input from a Notification
-      </a></div>
-  </li>
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/wear/notifications/pages.html">Adding Pages to a Notification
-      </a></div>
-  </li>
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/wear/notifications/stacks.html">Stacking Notifications
-      </a></div>
-  </li>
-
-  <li class="nav-section">
-    <div class="nav-section-header"><a href="/reference/android/preview/support/package-summary.html">Notification Reference</a></div>
-    <ul class="tree-list-children">
-<li class="nav-section">
-<div class="nav-section-header-ref"><span class="tree-list-subtitle package" title="android.preview.support.v4.app">android.preview.support.v4.app</span></div>
-  <ul>
-<li><a href="/reference/android/preview/support/v4/app/NotificationManagerCompat.html">NotificationManagerCompat</a></li>
-  </ul>
-</li>
-
-<li class="nav-section">
-<div class="nav-section-header-ref"><span class="tree-list-subtitle package" title="android.preview.support.wearable.notifications">android.preview.support.wearable.notifications</span></div>
-<ul>
-
-<li><a href="/reference/android/preview/support/wearable/notifications/RemoteInput.html">RemoteInput</a></li>
-<li><a href="/reference/android/preview/support/wearable/notifications/RemoteInput.Builder.html" >RemoteInput.Builder</a></li>
-
-<li><a href="/reference/android/preview/support/wearable/notifications/WearableNotifications.html">WearableNotifications</a></li>
-
-<li><a href="/reference/android/preview/support/wearable/notifications/WearableNotifications.Action.html">WearableNotifications.Action</a></li>
-
-<li><a href="/reference/android/preview/support/wearable/notifications/WearableNotifications.Action.Builder.html">WearableNotifications.Action.Builder</a></li>
-
-<li><a href="/reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html">WearableNotifications.Builder</a></li>
-	</ul>
-  </li>
-</ul>
-</li>
-
-
-
-  <li class="nav-section">
-    <div class="nav-section-header empty"><a href="/wear/license.html">License Agreement</a></div>
-  </li>
-
-
-</ul>
-
-        
-
-      </div>
-    </div> <!-- end side-nav -->
-    <script>
-      $(document).ready(function() {
-        scrollIntoView("devdoc-nav");
-        });
-    </script>
-
-
-
-
-<div class="col-12" id="doc-col" >
-
-
-  
-    
-      
-        <h1 itemprop="name" >Get Started with the Developer Preview</h1>
-      
-    
-  
-
-
-  
-  <div id="jd-content">
-
-
-    <div class="jd-descr" itemprop="articleBody">
-    <div class="cols">
-
-  <div class="col-5">
-<p>The Android Wear Developer Preview includes tools and APIs that allow you to
-enhance your app notifications
-to provide an optimized user experience on Android wearables.</p>
-
-<p>With the Android Wear Developer Preview, you can:</p>
-
-<ul>
-  <li>Run the Android Wear platform in the Android emulator.</li>
-  <li>Connect your Android device to the emulator and view notifications from the
-device as cards on Android Wear.</li>
-  <li>Try new APIs in the preview support library that enhance your app's notifications
-with features such as voice replies and notification pages.</li>
-</ul>
-
-<p>To get access to the Developer Preview tools,
-click the sign up button on the right, then follow the setup instructions below.</p>
-  </div>
-
-  <div class="col-7">
-<img src="/wear/images/laptop-bridge.png" width="400" height="222" alt="" />
-
-<a href="/wear/preview/signup.html" class="button" style="
-    width: 370px;
-    margin: 10px 0 20px;
-    font-weight: bold;
-    font-size: 16px;
-">Sign Up for the Developer Preview</a>
-
-<p>Signing up provides you access to:</p>
-<ul>
-<li>New notification APIs in the preview support library.</li>
-<li>Sample apps using the new notification APIs.</li>
-<li>The <em>Android Wear Preview</em> app for your mobile device, which connects
-your device to the Android Wear emulator.</li>
-</ul>
-
-  </div>
-</div>
-
-
-<p class="caution"><strong>Caution:</strong>
-The current Android Wear Developer Preview is intended for <b>development and testing purposes only</b>, not for production apps. Google may change this Developer Preview significantly prior to the official release of the Android Wear SDK. You may not publicly distribute or ship any application using this Developer Preview, as this Developer Preview will no longer be supported after the official SDK is released (which will cause applications based only on the Developer Preview to break).</p>
-
-
-
-
-<h2 id="Prereq">Prerequisites</h2>
-
-<p>Before you begin the setup, you must:</p>
-
-<ol>
-  <li><a href="/sdk/index.html"><b>Install the Android SDK</b></a>.
-  <p>The Android SDK includes all the developer tools required to build
-apps for Android (optional IDEs are also available for download).</p></li>
-  <li><a href="/wear/preview/signup.html"><b>Sign up for the Android Wear Developer Preview</b></a>.
-  <p>You must sign up with a Gmail or other Google account in order to download the
-preview support library and receive access to the
-<em>Android Wear Preview</em> beta app on Google Play Store.</p></li>
-</ol>
-
-<p class="note"><strong>Note:</strong>
-If you're using the ADT plugin for Eclipse, you must update to version 22.6.1 or higher.
-If you're using Android Studio, you must update to version 0.5.1 or higher</p>
-
-
-
-<h2 id="Install">1. Install the Android Wear System Image</h2>
-
-
-<ol>
-  <li>Launch <a href="/tools/help/sdk-manager.html"
-    >Android SDK Manager</a>.
-  <ul>
-    <li>From Eclipse, select <b>Window > Android SDK Manager</b>.</li>
-    <li>From Android Studio, select <b>Tools > Android > SDK Manager</b>.</li>
-  </ul>
-  </li>
-  <li>Below Tools, verify that you have Android SDK Tools revision 22.6 or higher.
-    <p>If your version of Android SDK Tools is lower than 22.6, you must update:</p>
-    <ol>
-      <li>Select <strong>Android SDK Tools</strong>.</li>
-      <li>Click <strong>Install package</strong>.</li>
-      <li>Accept the license and click <strong>Install</strong>.</li>
-      <li>When the installation completes, restart Android SDK Manager.</li>
-    </ol>
-  </li>
-
-  <li>Below Android 4.4.2, select <strong>Android Wear ARM EABI v7a System Image</strong>.
-<p class="note"><strong>Note:</strong> Android Wear is designed to support multiple processor architectures.
-</p></li>
-  <li>Below Extras, ensure that you have the latest version of the
-<a href="/tools/support-library/index.html">Android Support Library</a>.
-    If an update is available, select <strong>Android Support Library</strong>. If you're using Android Studio, also select <strong>Android Support Repository</strong>.</li>
-  <li>Click <strong>Install packages</strong>.</li>
-  <li>Accept the license and click <strong>Install</strong>.</li>
-</ol>
-
-
-
-<h2 id="SetupEmulator">2. Set Up the Android Wear Emulator</h2>
-
-<ol>
-<li>Launch the <a href="/tools/help/avd-manager.html"
-  >Android Virtual Device Manager</a>.
-<ul>
-<li>From Eclipse, select <b>Window > Android Virtual Device Manager</b>.</li>
-<li>From Android Studio, select <b>Tools > Android > AVD Manager</b>.</li>
-</ul>
-</li>
-<li>Click <strong>New</strong>.</li>
-<li>For the AVD Name, enter "AndroidWearSquare" or "AndroidWearRound", depending on whether
-you want to create an emulator with a square or round display.</li>
-<li>For the Device, select <strong>Android Wear Square</strong> or
-	<strong>Android Wear Round</strong>.</li>
-<li>For the Target, select <strong>Android 4.4.2 - API Level 19</strong> (or higher).</li>
-<li>For the CPU/ABI, select <strong>Android Wear ARM (armeabi-v7a)</strong>.
-<p class="note"><strong>Note:</strong> Android Wear is designed to support multiple processor architectures.
-</p></li>
-<li>For the Skin, select <strong>AndroidWearSquare</strong> or
-<strong>AndroidWearRound</strong>.</li>
-<li>Leave all other options set to their defaults and click <strong>OK</strong>.
-  <p>Although real Android wearables do not provide a keyboard as an input method,
-    you should keep <strong>Hardware keyboard present</strong> selected so you can
-    provide text input on screens where users will instead provide voice input.</p>
-</li>
-<!--
-<li>Click <strong>Device Definitions</strong>.</li>
-<li>Select <strong>Android WearSquare</strong> then click <strong>Create AVD</strong>.</li>
-<li>Click <strong>OK</strong>.</li>
--->
-<li>In the list of AVDs, select the one you just created and click
- <strong>Start</strong>. In the following window, click <strong>Launch</strong>.</li>
-</ol>
-
-<p>The Android Wear emulator now starts. To begin testing your app's notifications,
-you must now pair the emulator to your development device
-that has the <em>Android Wear Preview</em> app installed.</p>
-
-<p class="note"><strong>Tip:</strong> To improve the emulator startup time, edit your AVD
-and enable <strong>Snapshot</strong> under Emulator Options. When you start the emulator,
-select <strong>Save to snapshot</strong> then click <strong>Launch</strong>. Once the emulator
-is running, close it to save a snapshot of the system.
-Start the AVD again, but select <strong>Launch from snapshot</strong> and
-deselect <strong>Save to snapshot</strong>.</p>
-
-<p class="caution"><strong>Caution:</strong> Do not install apps on the Android Wear emulator.
-The system does not support traditional Android apps and the result of running such apps is
-unpredictable.</p>
-
-
-
-<h2 id="SetupApp">3. Set Up the Android Wear Preview App</h2>
-
-<p>To view your app's notifications on the Android Wear emulator, you must have the
-<em>Android Wear Preview</em> app installed on your Android device (a phone or tablet).</p>
-
-<p>To receive the Android Wear Preview app, you must <a
-href="/wear/preview/signup.html">sign up for the Developer Preview</a> using the same
-Gmail or Google account you use with Google Play Store.</p>
-</p>
-
-<p class="note"><strong>Note:</strong> The <em>Android Wear Preview</em> app is compatible with
-    Android 4.3 and higher and is not available for the Android emulator.</p>
-
-<p>After you've signed up for the Developer Preview,
-  you'll receive a confirmation email that includes a link to opt-in to the
-  <em>Android Wear Preview</em> app beta program. Once you opt-in, it may take up to 24 hours for the
-  app to become available in Google Play Store.</p>
-
-<p>After you install the <em>Android Wear Preview</em> app, you can set up
-  your device to communicate with the Android Wear emulator:</p>
-
-<ol>
-<li>Open the <em>Android Wear Preview</em> app. You should see a notice that the app is currently
-  not enabled as a notification listener. Tap the message to open the system settings,
-  then select Android Wear Preview to grant it notification access.</li>
-<li>Connect your device to your development machine over USB. Be sure that no other
- Android devices are connected to the machine.</li>
-<li>Ensure that the Android Wear emulator (created in the previous section) is running.
-The emulator should show the time and an icon that indicates no device is connected.</li>
-<li>Open a command line terminal, navigate to your Android SDK's <code>platform-tools/</code>
-directory, then execute:
-<pre style="margin-top:.5em">adb -d forward tcp:5601 tcp:5601</pre>
-<p class="note"><strong>Note:</strong> You must execute this command each time you connect your
-device over USB.</p>
-</li>
-<li>Return to the Android Wear Preview app. It should now indicate that it is connected to
-  the emulator. The Android Wear emulator should now show the 'g' orb icon, indicating
-  that is is connected to your device.
-</ol>
-
-<p>Now, notifications from your device also appear in the Android Wear emulator.</p>
-
-
-
-
-<h2 id="AddLibrary">4. Add the Support Library to Your Project</h2>
-
-<p>The Android Wear preview support library includes several APIs that allow you to
-optimize your app's notifications for the Android Wear user experience.</p>
-
-<p>To receive the preview support library, you must <a
-href="/wear/preview/signup.html">sign up for the Developer Preview</a>. The
-confirmation email you receive after you sign up includes a link to download a ZIP file,
-which contains the preview support library and some sample apps.</p>
-
-<p>After you download and unzip the package, add the preview support library
-sto your Android project:</p>
-
-<p><b>If you're using Eclipse:</b></p>
-    <ol>
-      <li>In your Android app project, create a <code>libs/</code> directory in your project root
-    (the same location as the <code>AndroidManifest.xml</code> file).</li>
-      <li>Copy the v4 support library JAR file from your Android SDK directory (e.g.,
-        <code>&lt;sdk&gt;/extras/android/support/v4/android-support-v4.jar</code>) into your
-        project <code>libs/</code> directory.
-      <li>Also save the <code>wearable-preview-support.jar</code> file in the <code>libs/</code> directory.
-      <li>Right click each JAR file and select <strong>Build Path &gt; Add to Build Path</strong>.</li>
-    </ol>
-
- <p><b>If you're using Android Studio:</b></p>
-    <ol>
-     <li>In your Android app project, create a <code>libs/</code> directory in your project root
-    (the same location as the <code>AndroidManifest.xml</code> file).</li>
-      <li>Save the <code>wearable-preview-support.jar</code> file in the <code>libs/</code> directory.
-      <li>Open the <code>build.gradle</code> file in your app module.</li>
-      <li>Add a dependency rule for both the v4 support library and the Android Wear
-      preview support library:
-<pre>
-dependencies {
-    compile "com.android.support:support-v4:18.0.+"
-    compile files('../libs/wearable-preview-support.jar')
-}
-</pre>
-      </li>
-      <li>Click <strong>Sync Project with Gradle Files</strong> in the toolbar.</li>
-    </ol>
-
-<p>To start optimizing your notifications for Android Wear,
-  read <a href="/wear/notifications/creating.html"
-  >Creating Notifications for Android Wear</a>.</p>
-
-
-
-</body>
-</html>
-
-    </div>
-
-      <div class="content-footer layout-content-row"
-                    itemscope itemtype="http://schema.org/SiteNavigationElement">
-        <div class="layout-content-col col-9" style="padding-top:4px">
-          
-            <div class="g-plusone" data-size="medium"></div>
-          
-        </div>
-        
-        <div class="paging-links layout-content-col col-4">
-          
-        </div>
-        
-      </div>
-
-      
-      
-
-  </div> <!-- end jd-content -->
-
-<div id="footer" class="wrap" >
-        
-
-  <div id="copyright">
-    
-  Except as noted, this content is 
-  licensed under <a href="http://creativecommons.org/licenses/by/2.5/">
-  Creative Commons Attribution 2.5</a>. For details and 
-  restrictions, see the <a href="/license.html">Content 
-  License</a>.
-  </div>
-
-
-  <div id="footerlinks">
-    
-  <p>
-    <a href="/about/index.html">About Android</a>&nbsp;&nbsp;|&nbsp;
-    <a href="/legal.html">Legal</a>&nbsp;&nbsp;|&nbsp;
-    <a href="/support.html">Support</a>
-  </p>
-  </div>
-
-</div> <!-- end footer -->
-</div><!-- end doc-content -->
-
-</div> <!-- end body-content --> 
-
-
-
-
-
-
-<!-- Start of Tag -->
-<script type="text/javascript">
-var axel = Math.random() + "";
-var a = axel * 10000000000000;
-document.write('<iframe src="https://2507573.fls.doubleclick.net/activityi;src=2507573;type=other026;cat=googl348;ord=' + a + '?" width="1" height="1" frameborder="0" style="display:none"></iframe>');
-</script>
-<noscript>
-<iframe src="https://2507573.fls.doubleclick.net/activityi;src=2507573;type=other026;cat=googl348;ord=1?" width="1" height="1" frameborder="0" style="display:none"></iframe>
-</noscript>
-<!-- End of Tag -->
-</body>
-</html>
-
-
-
diff --git a/docs/html/wear/preview/start.jd b/docs/html/wear/preview/start.jd
new file mode 100644
index 0000000..f8f0129
--- /dev/null
+++ b/docs/html/wear/preview/start.jd
@@ -0,0 +1,254 @@
+page.title=Get Started with the Developer Preview
+
+@jd:body
+
+
+<div class="cols">
+
+  <div class="col-5">
+<p>The Android Wear Developer Preview includes tools and APIs that allow you to
+enhance your app notifications
+to provide an optimized user experience on Android wearables.</p>
+
+<p>With the Android Wear Developer Preview, you can:</p>
+
+<ul>
+  <li>Run the Android Wear platform in the Android emulator.</li>
+  <li>Connect your Android device to the emulator and view notifications from the
+device as cards on Android Wear.</li>
+  <li>Try new APIs in the preview support library that enhance your app's notifications
+with features such as voice replies and notification pages.</li>
+</ul>
+
+<p>To get access to the Developer Preview tools,
+click the sign up button on the right, then follow the setup instructions below.</p>
+  </div>
+
+  <div class="col-7">
+<img src="/wear/images/laptop-bridge.png" width="400" height="222" alt="" />
+
+<a href="/wear/preview/signup.html" class="button" style="
+    width: 370px;
+    margin: 10px 0 20px;
+    font-weight: bold;
+    font-size: 16px;
+">Sign Up for the Developer Preview</a>
+
+<p>Signing up provides you access to:</p>
+<ul>
+<li>New notification APIs in the preview support library.</li>
+<li>Sample apps using the new notification APIs.</li>
+<li>The <em>Android Wear Preview</em> app for your mobile device, which connects
+your device to the Android Wear emulator.</li>
+</ul>
+
+  </div>
+</div>
+
+
+<p class="caution"><strong>Caution:</strong>
+The current Android Wear Developer Preview is intended for <b>development and testing purposes only</b>, not for production apps. Google may change this Developer Preview significantly prior to the official release of the Android Wear SDK. You may not publicly distribute or ship any application using this Developer Preview, as this Developer Preview will no longer be supported after the official SDK is released (which will cause applications based only on the Developer Preview to break).</p>
+
+
+
+
+<h2 id="Prereq">Prerequisites</h2>
+
+<p>Before you begin the setup, you must:</p>
+
+<ol>
+  <li><a href="{@docRoot}sdk/index.html"><b>Install the Android SDK</b></a>.
+  <p>The Android SDK includes all the developer tools required to build
+apps for Android (optional IDEs are also available for download).</p></li>
+  <li><a href="{@docRoot}wear/preview/signup.html"><b>Sign up for the Android Wear Developer Preview</b></a>.
+  <p>You must sign up with a Gmail or other Google account in order to download the
+preview support library and receive access to the
+<em>Android Wear Preview</em> beta app on Google Play Store.</p></li>
+</ol>
+
+<p class="note"><strong>Note:</strong>
+If you're using the ADT plugin for Eclipse, you must update to version 22.6.1 or higher.
+If you're using Android Studio, you must update to version 0.5.1 or higher</p>
+
+
+
+<h2 id="Install">1. Install the Android Wear System Image</h2>
+
+
+<ol>
+  <li>Launch <a href="{@docRoot}tools/help/sdk-manager.html"
+    >Android SDK Manager</a>.
+  <ul>
+    <li>From Eclipse, select <b>Window > Android SDK Manager</b>.</li>
+    <li>From Android Studio, select <b>Tools > Android > SDK Manager</b>.</li>
+  </ul>
+  </li>
+  <li>Below Tools, verify that you have Android SDK Tools revision 22.6 or higher.
+    <p>If your version of Android SDK Tools is lower than 22.6, you must update:</p>
+    <ol>
+      <li>Select <strong>Android SDK Tools</strong>.</li>
+      <li>Click <strong>Install package</strong>.</li>
+      <li>Accept the license and click <strong>Install</strong>.</li>
+      <li>When the installation completes, restart Android SDK Manager.</li>
+    </ol>
+  </li>
+
+  <li>Below Android 4.4.2, select <strong>Android Wear ARM EABI v7a System Image</strong>.
+<p class="note"><strong>Note:</strong> Android Wear is designed to support multiple processor architectures.
+</p></li>
+  <li>Below Extras, ensure that you have the latest version of the
+<a href="{@docRoot}tools/support-library/index.html">Android Support Library</a>.
+    If an update is available, select <strong>Android Support Library</strong>. If you're using Android Studio, also select <strong>Android Support Repository</strong>.</li>
+  <li>Click <strong>Install packages</strong>.</li>
+  <li>Accept the license and click <strong>Install</strong>.</li>
+</ol>
+
+
+
+<h2 id="SetupEmulator">2. Set Up the Android Wear Emulator</h2>
+
+<ol>
+<li>Launch the <a href="{@docRoot}tools/help/avd-manager.html"
+  >Android Virtual Device Manager</a>.
+<ul>
+<li>From Eclipse, select <b>Window > Android Virtual Device Manager</b>.</li>
+<li>From Android Studio, select <b>Tools > Android > AVD Manager</b>.</li>
+</ul>
+</li>
+<li>Click <strong>New</strong>.</li>
+<li>For the AVD Name, enter "AndroidWearSquare" or "AndroidWearRound", depending on whether
+you want to create an emulator with a square or round display.</li>
+<li>For the Device, select <strong>Android Wear Square</strong> or
+	<strong>Android Wear Round</strong>.</li>
+<li>For the Target, select <strong>Android 4.4.2 - API Level 19</strong> (or higher).</li>
+<li>For the CPU/ABI, select <strong>Android Wear ARM (armeabi-v7a)</strong>.
+<p class="note"><strong>Note:</strong> Android Wear is designed to support multiple processor architectures.
+</p></li>
+<li>For the Skin, select <strong>AndroidWearSquare</strong> or
+<strong>AndroidWearRound</strong>.</li>
+<li>Leave all other options set to their defaults and click <strong>OK</strong>.
+  <p>Although real Android wearables do not provide a keyboard as an input method,
+    you should keep <strong>Hardware keyboard present</strong> selected so you can
+    provide text input on screens where users will instead provide voice input.</p>
+</li>
+<!--
+<li>Click <strong>Device Definitions</strong>.</li>
+<li>Select <strong>Android WearSquare</strong> then click <strong>Create AVD</strong>.</li>
+<li>Click <strong>OK</strong>.</li>
+-->
+<li>In the list of AVDs, select the one you just created and click
+ <strong>Start</strong>. In the following window, click <strong>Launch</strong>.</li>
+</ol>
+
+<p>The Android Wear emulator now starts. To begin testing your app's notifications,
+you must now pair the emulator to your development device
+that has the <em>Android Wear Preview</em> app installed.</p>
+
+<p class="note"><strong>Tip:</strong> To improve the emulator startup time, edit your AVD
+and enable <strong>Snapshot</strong> under Emulator Options. When you start the emulator,
+select <strong>Save to snapshot</strong> then click <strong>Launch</strong>. Once the emulator
+is running, close it to save a snapshot of the system.
+Start the AVD again, but select <strong>Launch from snapshot</strong> and
+deselect <strong>Save to snapshot</strong>.</p>
+
+<p class="caution"><strong>Caution:</strong> Do not install apps on the Android Wear emulator.
+The system does not support traditional Android apps and the result of running such apps is
+unpredictable.</p>
+
+
+
+<h2 id="SetupApp">3. Set Up the Android Wear Preview App</h2>
+
+<p>To view your app's notifications on the Android Wear emulator, you must have the
+<em>Android Wear Preview</em> app installed on your Android device (a phone or tablet).</p>
+
+<p>To receive the Android Wear Preview app, you must <a
+href="{@docRoot}wear/preview/signup.html">sign up for the Developer Preview</a> using the same
+Gmail or Google account you use with Google Play Store.</p>
+</p>
+
+<p class="note"><strong>Note:</strong> The <em>Android Wear Preview</em> app is compatible with
+    Android 4.3 and higher and is not available for the Android emulator.</p>
+
+<p>After you've signed up for the Developer Preview,
+  you'll receive a confirmation email that includes a link to opt-in to the
+  <em>Android Wear Preview</em> app beta program. Once you opt-in, it may take up to 24 hours for the
+  app to become available in Google Play Store.</p>
+
+<p>After you install the <em>Android Wear Preview</em> app, you can set up
+  your device to communicate with the Android Wear emulator:</p>
+
+<ol>
+<li>Open the <em>Android Wear Preview</em> app. You should see a notice that the app is currently
+  not enabled as a notification listener. Tap the message to open the system settings,
+  then select Android Wear Preview to grant it notification access.</li>
+<li>Connect your device to your development machine over USB. Be sure that no other
+ Android devices are connected to the machine.</li>
+<li>Ensure that the Android Wear emulator (created in the previous section) is running.
+The emulator should show the time and an icon that indicates no device is connected.</li>
+<li>Open a command line terminal, navigate to your Android SDK's <code>platform-tools/</code>
+directory, then execute:
+<pre style="margin-top:.5em">adb -d forward tcp:5601 tcp:5601</pre>
+<p class="note"><strong>Note:</strong> You must execute this command each time you connect your
+device over USB.</p>
+</li>
+<li>Return to the Android Wear Preview app. It should now indicate that it is connected to
+  the emulator. The Android Wear emulator should now show the 'g' orb icon, indicating
+  that is is connected to your device.
+</ol>
+
+<p>Now, notifications from your device also appear in the Android Wear emulator.</p>
+
+
+
+
+<h2 id="AddLibrary">4. Add the Support Library to Your Project</h2>
+
+<p>The Android Wear preview support library includes several APIs that allow you to
+optimize your app's notifications for the Android Wear user experience.</p>
+
+<p>To receive the preview support library, you must <a
+href="{@docRoot}wear/preview/signup.html">sign up for the Developer Preview</a>. The
+confirmation email you receive after you sign up includes a link to download a ZIP file,
+which contains the preview support library and some sample apps.</p>
+
+<p>After you download and unzip the package, add the preview support library
+sto your Android project:</p>
+
+<p><b>If you're using Eclipse:</b></p>
+    <ol>
+      <li>In your Android app project, create a <code>libs/</code> directory in your project root
+    (the same location as the <code>AndroidManifest.xml</code> file).</li>
+      <li>Copy the v4 support library JAR file from your Android SDK directory (e.g.,
+        <code>&lt;sdk&gt;/extras/android/support/v4/android-support-v4.jar</code>) into your
+        project <code>libs/</code> directory.
+      <li>Also save the <code>wearable-preview-support.jar</code> file in the <code>libs/</code> directory.
+      <li>Right click each JAR file and select <strong>Build Path &gt; Add to Build Path</strong>.</li>
+    </ol>
+
+ <p><b>If you're using Android Studio:</b></p>
+    <ol>
+     <li>In your Android app project, create a <code>libs/</code> directory in your project root
+    (the same location as the <code>AndroidManifest.xml</code> file).</li>
+      <li>Save the <code>wearable-preview-support.jar</code> file in the <code>libs/</code> directory.
+      <li>Open the <code>build.gradle</code> file in your app module.</li>
+      <li>Add a dependency rule for both the v4 support library and the Android Wear
+      preview support library:
+<pre>
+dependencies {
+    compile "com.android.support:support-v4:18.0.+"
+    compile files('../libs/wearable-preview-support.jar')
+}
+</pre>
+      </li>
+      <li>Click <strong>Sync Project with Gradle Files</strong> in the toolbar.</li>
+    </ol>
+
+<p>To start optimizing your notifications for Android Wear,
+  read <a href="{@docRoot}wear/notifications/creating.html"
+  >Creating Notifications for Android Wear</a>.</p>
+
+
+
+</body>
+</html>
diff --git a/docs/html/wear/wear_toc.cs b/docs/html/wear/wear_toc.cs
new file mode 100644
index 0000000..65ac2e9
--- /dev/null
+++ b/docs/html/wear/wear_toc.cs
@@ -0,0 +1,74 @@
+<ul id="nav">
+
+  <li class="nav-section">
+    <div class="nav-section-header empty"><a href="<?cs var:toroot ?>wear/preview/start.html">Get Started
+      </a></div>
+  </li>
+
+  <li class="nav-section">
+    <div class="nav-section-header empty"><a href="<?cs var:toroot ?>wear/design/user-interface.html">UI Overview
+      </a></div>
+  </li>
+
+  <li class="nav-section">
+    <div class="nav-section-header empty"><a href="<?cs var:toroot ?>wear/design/index.html">Design Principles
+      </a></div>
+  </li>
+
+  <li class="nav-section">
+    <div class="nav-section-header empty"><a href="<?cs var:toroot ?>wear/notifications/creating.html">Creating Notifications for Android Wear
+      </a></div>
+  </li>
+
+  <li class="nav-section">
+    <div class="nav-section-header empty"><a href="<?cs var:toroot ?>wear/notifications/remote-input.html">Receiving Voice Input from a Notification
+      </a></div>
+  </li>
+
+  <li class="nav-section">
+    <div class="nav-section-header empty"><a href="<?cs var:toroot ?>wear/notifications/pages.html">Adding Pages to a Notification
+      </a></div>
+  </li>
+
+  <li class="nav-section">
+    <div class="nav-section-header empty"><a href="<?cs var:toroot ?>wear/notifications/stacks.html">Stacking Notifications
+      </a></div>
+  </li>
+
+  <li class="nav-section">
+    <div class="nav-section-header"><a href="<?cs var:toroot ?>reference/android/preview/support/package-summary.html">Notification Reference</a></div>
+    <ul class="tree-list-children">
+<li class="nav-section">
+<div class="nav-section-header-ref"><span class="tree-list-subtitle package" title="android.preview.support.v4.app">android.preview.support.v4.app</span></div>
+  <ul>
+<li><a href="<?cs var:toroot ?>reference/android/preview/support/v4/app/NotificationManagerCompat.html">NotificationManagerCompat</a></li>
+  </ul>
+</li>
+
+<li class="nav-section">
+<div class="nav-section-header-ref"><span class="tree-list-subtitle package" title="android.preview.support.wearable.notifications">android.preview.support.wearable.notifications</span></div>
+<ul>
+
+<li><a href="<?cs var:toroot ?>reference/android/preview/support/wearable/notifications/RemoteInput.html">RemoteInput</a></li>
+<li><a href="<?cs var:toroot ?>reference/android/preview/support/wearable/notifications/RemoteInput.Builder.html" >RemoteInput.Builder</a></li>
+
+<li><a href="<?cs var:toroot ?>reference/android/preview/support/wearable/notifications/WearableNotifications.html">WearableNotifications</a></li>
+
+<li><a href="<?cs var:toroot ?>reference/android/preview/support/wearable/notifications/WearableNotifications.Action.html">WearableNotifications.Action</a></li>
+
+<li><a href="<?cs var:toroot ?>reference/android/preview/support/wearable/notifications/WearableNotifications.Action.Builder.html">WearableNotifications.Action.Builder</a></li>
+
+<li><a href="<?cs var:toroot ?>reference/android/preview/support/wearable/notifications/WearableNotifications.Builder.html">WearableNotifications.Builder</a></li>
+	</ul>
+  </li>
+</ul>
+</li>
+
+
+
+  <li class="nav-section">
+    <div class="nav-section-header empty"><a href="<?cs var:toroot ?>wear/license.html">License Agreement</a></div>
+  </li>
+
+
+</ul>
diff --git a/docs/image_sources/gcm/CCS-ack.graffle b/docs/image_sources/gcm/CCS-ack.graffle
new file mode 100644
index 0000000..addd456
--- /dev/null
+++ b/docs/image_sources/gcm/CCS-ack.graffle
@@ -0,0 +1,1580 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>ActiveLayerIndex</key>
+	<integer>0</integer>
+	<key>ApplicationVersion</key>
+	<array>
+		<string>com.omnigroup.OmniGrafflePro</string>
+		<string>139.18.0.187838</string>
+	</array>
+	<key>AutoAdjust</key>
+	<true/>
+	<key>BackgroundGraphic</key>
+	<dict>
+		<key>Bounds</key>
+		<string>{{0, 0}, {576.00002479553223, 733}}</string>
+		<key>Class</key>
+		<string>SolidGraphic</string>
+		<key>FontInfo</key>
+		<dict>
+			<key>Font</key>
+			<string>Helvetica</string>
+			<key>Size</key>
+			<real>12</real>
+		</dict>
+		<key>ID</key>
+		<integer>2</integer>
+		<key>Style</key>
+		<dict>
+			<key>shadow</key>
+			<dict>
+				<key>Draws</key>
+				<string>NO</string>
+			</dict>
+			<key>stroke</key>
+			<dict>
+				<key>Draws</key>
+				<string>NO</string>
+			</dict>
+		</dict>
+	</dict>
+	<key>BaseZoom</key>
+	<integer>0</integer>
+	<key>CanvasOrigin</key>
+	<string>{0, 0}</string>
+	<key>ColumnAlign</key>
+	<integer>1</integer>
+	<key>ColumnSpacing</key>
+	<real>36</real>
+	<key>CreationDate</key>
+	<string>2013-08-08 01:54:22 +0000</string>
+	<key>Creator</key>
+	<string>Katie McCormick</string>
+	<key>DisplayScale</key>
+	<string>1 0/72 in = 1.0000 in</string>
+	<key>GraphDocumentVersion</key>
+	<integer>8</integer>
+	<key>GraphicsList</key>
+	<array>
+		<dict>
+			<key>Bounds</key>
+			<string>{{89, 329}, {169, 44}}</string>
+			<key>Class</key>
+			<string>ShapedGraphic</string>
+			<key>FitText</key>
+			<string>YES</string>
+			<key>Flow</key>
+			<string>Resize</string>
+			<key>ID</key>
+			<integer>250</integer>
+			<key>Shape</key>
+			<string>Rectangle</string>
+			<key>Style</key>
+			<dict>
+				<key>fill</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+				<key>shadow</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+				<key>stroke</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+			</dict>
+			<key>Text</key>
+			<dict>
+				<key>Text</key>
+				<string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs28 \cf0 Now app server can send\
+message no. 101}</string>
+			</dict>
+			<key>Wrap</key>
+			<string>NO</string>
+		</dict>
+		<dict>
+			<key>Bounds</key>
+			<string>{{102, 266}, {114, 44}}</string>
+			<key>Class</key>
+			<string>ShapedGraphic</string>
+			<key>FitText</key>
+			<string>YES</string>
+			<key>Flow</key>
+			<string>Resize</string>
+			<key>ID</key>
+			<integer>249</integer>
+			<key>Shape</key>
+			<string>Rectangle</string>
+			<key>Style</key>
+			<dict>
+				<key>fill</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+				<key>shadow</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+				<key>stroke</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+			</dict>
+			<key>Text</key>
+			<dict>
+				<key>Text</key>
+				<string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs28 \cf0 App server waits\
+for ack 1}</string>
+			</dict>
+			<key>Wrap</key>
+			<string>NO</string>
+		</dict>
+		<dict>
+			<key>Bounds</key>
+			<string>{{153, 154}, {98, 44}}</string>
+			<key>Class</key>
+			<string>ShapedGraphic</string>
+			<key>FitText</key>
+			<string>YES</string>
+			<key>Flow</key>
+			<string>Resize</string>
+			<key>ID</key>
+			<integer>244</integer>
+			<key>Shape</key>
+			<string>Rectangle</string>
+			<key>Style</key>
+			<dict>
+				<key>fill</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+				<key>shadow</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+				<key>stroke</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+			</dict>
+			<key>Text</key>
+			<dict>
+				<key>Text</key>
+				<string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs28 \cf0 Average\
+response time}</string>
+			</dict>
+			<key>Wrap</key>
+			<string>NO</string>
+		</dict>
+		<dict>
+			<key>Class</key>
+			<string>LineGraphic</string>
+			<key>Head</key>
+			<dict>
+				<key>ID</key>
+				<integer>226</integer>
+				<key>Position</key>
+				<real>0.375</real>
+			</dict>
+			<key>ID</key>
+			<integer>242</integer>
+			<key>Points</key>
+			<array>
+				<string>{263.00000095367432, 314.5}</string>
+				<string>{261, 99}</string>
+			</array>
+			<key>Style</key>
+			<dict>
+				<key>stroke</key>
+				<dict>
+					<key>Color</key>
+					<dict>
+						<key>b</key>
+						<string>0.112257</string>
+						<key>g</key>
+						<string>0.107007</string>
+						<key>r</key>
+						<string>0.934433</string>
+					</dict>
+					<key>HeadArrow</key>
+					<string>FilledArrow</string>
+					<key>Legacy</key>
+					<true/>
+					<key>TailArrow</key>
+					<string>0</string>
+				</dict>
+			</dict>
+			<key>Tail</key>
+			<dict>
+				<key>ID</key>
+				<integer>227</integer>
+				<key>Position</key>
+				<real>0.34722220897674561</real>
+			</dict>
+		</dict>
+		<dict>
+			<key>Class</key>
+			<string>LineGraphic</string>
+			<key>Head</key>
+			<dict>
+				<key>ID</key>
+				<integer>227</integer>
+				<key>Position</key>
+				<real>0.3541666567325592</real>
+			</dict>
+			<key>ID</key>
+			<integer>241</integer>
+			<key>Points</key>
+			<array>
+				<string>{261, 99}</string>
+				<string>{262.50000071525574, 314.5}</string>
+			</array>
+			<key>Style</key>
+			<dict>
+				<key>stroke</key>
+				<dict>
+					<key>Color</key>
+					<dict>
+						<key>b</key>
+						<string>0.112257</string>
+						<key>g</key>
+						<string>0.107007</string>
+						<key>r</key>
+						<string>0.934433</string>
+					</dict>
+					<key>HeadArrow</key>
+					<string>FilledArrow</string>
+					<key>Legacy</key>
+					<true/>
+					<key>TailArrow</key>
+					<string>0</string>
+				</dict>
+			</dict>
+			<key>Tail</key>
+			<dict>
+				<key>ID</key>
+				<integer>226</integer>
+				<key>Position</key>
+				<real>0.375</real>
+			</dict>
+		</dict>
+		<dict>
+			<key>Class</key>
+			<string>LineGraphic</string>
+			<key>Head</key>
+			<dict>
+				<key>ID</key>
+				<integer>227</integer>
+			</dict>
+			<key>ID</key>
+			<integer>240</integer>
+			<key>Points</key>
+			<array>
+				<string>{257.5, 336.5}</string>
+				<string>{288, 314.5}</string>
+			</array>
+			<key>Style</key>
+			<dict>
+				<key>stroke</key>
+				<dict>
+					<key>Color</key>
+					<dict>
+						<key>b</key>
+						<string>0.112257</string>
+						<key>g</key>
+						<string>0.107007</string>
+						<key>r</key>
+						<string>0.934433</string>
+					</dict>
+					<key>HeadArrow</key>
+					<string>FilledArrow</string>
+					<key>Legacy</key>
+					<true/>
+					<key>TailArrow</key>
+					<string>0</string>
+				</dict>
+			</dict>
+		</dict>
+		<dict>
+			<key>Class</key>
+			<string>LineGraphic</string>
+			<key>ID</key>
+			<integer>239</integer>
+			<key>Points</key>
+			<array>
+				<string>{231, 288.50000116229057}</string>
+				<string>{231, 251.25}</string>
+			</array>
+			<key>Style</key>
+			<dict>
+				<key>stroke</key>
+				<dict>
+					<key>Color</key>
+					<dict>
+						<key>b</key>
+						<string>0.112257</string>
+						<key>g</key>
+						<string>0.107007</string>
+						<key>r</key>
+						<string>0.934433</string>
+					</dict>
+					<key>HeadArrow</key>
+					<string>FilledArrow</string>
+					<key>Legacy</key>
+					<true/>
+					<key>TailArrow</key>
+					<string>0</string>
+				</dict>
+			</dict>
+			<key>Tail</key>
+			<dict>
+				<key>ID</key>
+				<integer>238</integer>
+				<key>Position</key>
+				<real>0.56800001859664917</real>
+			</dict>
+		</dict>
+		<dict>
+			<key>Class</key>
+			<string>LineGraphic</string>
+			<key>ID</key>
+			<integer>238</integer>
+			<key>Points</key>
+			<array>
+				<string>{231, 253}</string>
+				<string>{231, 315.5}</string>
+			</array>
+			<key>Style</key>
+			<dict>
+				<key>stroke</key>
+				<dict>
+					<key>Color</key>
+					<dict>
+						<key>b</key>
+						<string>0.112257</string>
+						<key>g</key>
+						<string>0.107007</string>
+						<key>r</key>
+						<string>0.934433</string>
+					</dict>
+					<key>HeadArrow</key>
+					<string>FilledArrow</string>
+					<key>Legacy</key>
+					<true/>
+					<key>TailArrow</key>
+					<string>0</string>
+				</dict>
+			</dict>
+		</dict>
+		<dict>
+			<key>Bounds</key>
+			<string>{{476, 33}, {49, 32}}</string>
+			<key>Class</key>
+			<string>ShapedGraphic</string>
+			<key>FitText</key>
+			<string>YES</string>
+			<key>Flow</key>
+			<string>Resize</string>
+			<key>FontInfo</key>
+			<dict>
+				<key>Font</key>
+				<string>Helvetica</string>
+				<key>Size</key>
+				<real>18</real>
+			</dict>
+			<key>ID</key>
+			<integer>230</integer>
+			<key>Shape</key>
+			<string>Rectangle</string>
+			<key>Style</key>
+			<dict>
+				<key>fill</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+				<key>shadow</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+				<key>stroke</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+			</dict>
+			<key>Text</key>
+			<dict>
+				<key>Text</key>
+				<string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs36 \cf0 CCS}</string>
+			</dict>
+			<key>Wrap</key>
+			<string>NO</string>
+		</dict>
+		<dict>
+			<key>Bounds</key>
+			<string>{{243, 35}, {101, 32}}</string>
+			<key>Class</key>
+			<string>ShapedGraphic</string>
+			<key>FitText</key>
+			<string>YES</string>
+			<key>Flow</key>
+			<string>Resize</string>
+			<key>FontInfo</key>
+			<dict>
+				<key>Font</key>
+				<string>Helvetica</string>
+				<key>Size</key>
+				<real>18</real>
+			</dict>
+			<key>ID</key>
+			<integer>229</integer>
+			<key>Shape</key>
+			<string>Rectangle</string>
+			<key>Style</key>
+			<dict>
+				<key>fill</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+				<key>shadow</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+				<key>stroke</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+			</dict>
+			<key>Text</key>
+			<dict>
+				<key>Text</key>
+				<string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs36 \cf0 App Server}</string>
+			</dict>
+			<key>Wrap</key>
+			<string>NO</string>
+		</dict>
+		<dict>
+			<key>Class</key>
+			<string>LineGraphic</string>
+			<key>ID</key>
+			<integer>228</integer>
+			<key>Points</key>
+			<array>
+				<string>{288, 252}</string>
+				<string>{216, 252}</string>
+			</array>
+			<key>Style</key>
+			<dict>
+				<key>stroke</key>
+				<dict>
+					<key>HeadArrow</key>
+					<string>0</string>
+					<key>Legacy</key>
+					<true/>
+					<key>TailArrow</key>
+					<string>0</string>
+				</dict>
+			</dict>
+		</dict>
+		<dict>
+			<key>Class</key>
+			<string>LineGraphic</string>
+			<key>ID</key>
+			<integer>227</integer>
+			<key>Points</key>
+			<array>
+				<string>{288, 314.5}</string>
+				<string>{216, 314.5}</string>
+			</array>
+			<key>Style</key>
+			<dict>
+				<key>stroke</key>
+				<dict>
+					<key>HeadArrow</key>
+					<string>0</string>
+					<key>Legacy</key>
+					<true/>
+					<key>TailArrow</key>
+					<string>0</string>
+				</dict>
+			</dict>
+		</dict>
+		<dict>
+			<key>Class</key>
+			<string>LineGraphic</string>
+			<key>ID</key>
+			<integer>226</integer>
+			<key>Points</key>
+			<array>
+				<string>{288, 99}</string>
+				<string>{216, 99}</string>
+			</array>
+			<key>Style</key>
+			<dict>
+				<key>stroke</key>
+				<dict>
+					<key>HeadArrow</key>
+					<string>0</string>
+					<key>Legacy</key>
+					<true/>
+					<key>TailArrow</key>
+					<string>0</string>
+				</dict>
+			</dict>
+		</dict>
+		<dict>
+			<key>Bounds</key>
+			<string>{{393.69128000000001, 348.37441999999999}, {57, 27}}</string>
+			<key>Class</key>
+			<string>ShapedGraphic</string>
+			<key>FitText</key>
+			<string>YES</string>
+			<key>Flow</key>
+			<string>Resize</string>
+			<key>ID</key>
+			<integer>223</integer>
+			<key>Rotation</key>
+			<real>23</real>
+			<key>Shape</key>
+			<string>Rectangle</string>
+			<key>Style</key>
+			<dict>
+				<key>fill</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+				<key>shadow</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+				<key>stroke</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+			</dict>
+			<key>Text</key>
+			<dict>
+				<key>Text</key>
+				<string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs28 \cf0 no. 101}</string>
+			</dict>
+			<key>Wrap</key>
+			<string>NO</string>
+		</dict>
+		<dict>
+			<key>Bounds</key>
+			<string>{{290.12054000000001, 420.17102}, {60, 27}}</string>
+			<key>Class</key>
+			<string>ShapedGraphic</string>
+			<key>FitText</key>
+			<string>YES</string>
+			<key>Flow</key>
+			<string>Resize</string>
+			<key>FontInfo</key>
+			<dict>
+				<key>Font</key>
+				<string>Helvetica</string>
+				<key>Size</key>
+				<real>14</real>
+			</dict>
+			<key>ID</key>
+			<integer>222</integer>
+			<key>Rotation</key>
+			<real>341</real>
+			<key>Shape</key>
+			<string>Rectangle</string>
+			<key>Style</key>
+			<dict>
+				<key>fill</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+				<key>shadow</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+				<key>stroke</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+			</dict>
+			<key>Text</key>
+			<dict>
+				<key>Text</key>
+				<string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs28 \cf0 ack 100}</string>
+			</dict>
+			<key>Wrap</key>
+			<string>NO</string>
+		</dict>
+		<dict>
+			<key>Class</key>
+			<string>LineGraphic</string>
+			<key>ID</key>
+			<integer>220</integer>
+			<key>Points</key>
+			<array>
+				<string>{504, 351}</string>
+				<string>{288, 463}</string>
+			</array>
+			<key>Style</key>
+			<dict>
+				<key>stroke</key>
+				<dict>
+					<key>Color</key>
+					<dict>
+						<key>b</key>
+						<string>0.934433</string>
+						<key>g</key>
+						<string>0</string>
+						<key>r</key>
+						<string>0.122713</string>
+					</dict>
+					<key>HeadArrow</key>
+					<string>FilledArrow</string>
+					<key>Legacy</key>
+					<true/>
+					<key>TailArrow</key>
+					<string>0</string>
+				</dict>
+			</dict>
+		</dict>
+		<dict>
+			<key>Bounds</key>
+			<string>{{430.51697000000001, 279.19488999999999}, {44, 27}}</string>
+			<key>Class</key>
+			<string>ShapedGraphic</string>
+			<key>FitText</key>
+			<string>YES</string>
+			<key>Flow</key>
+			<string>Resize</string>
+			<key>FontInfo</key>
+			<dict>
+				<key>Font</key>
+				<string>Helvetica</string>
+				<key>Size</key>
+				<real>14</real>
+			</dict>
+			<key>ID</key>
+			<integer>219</integer>
+			<key>Rotation</key>
+			<real>341</real>
+			<key>Shape</key>
+			<string>Rectangle</string>
+			<key>Style</key>
+			<dict>
+				<key>fill</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+				<key>shadow</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+				<key>stroke</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+			</dict>
+			<key>Text</key>
+			<dict>
+				<key>Text</key>
+				<string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs28 \cf0 ack.. }</string>
+			</dict>
+			<key>Wrap</key>
+			<string>NO</string>
+		</dict>
+		<dict>
+			<key>Bounds</key>
+			<string>{{390.63733000000002, 258.42700000000002}, {44, 27}}</string>
+			<key>Class</key>
+			<string>ShapedGraphic</string>
+			<key>FitText</key>
+			<string>YES</string>
+			<key>Flow</key>
+			<string>Resize</string>
+			<key>FontInfo</key>
+			<dict>
+				<key>Font</key>
+				<string>Helvetica</string>
+				<key>Size</key>
+				<real>14</real>
+			</dict>
+			<key>ID</key>
+			<integer>218</integer>
+			<key>Rotation</key>
+			<real>341</real>
+			<key>Shape</key>
+			<string>Rectangle</string>
+			<key>Style</key>
+			<dict>
+				<key>fill</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+				<key>shadow</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+				<key>stroke</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+			</dict>
+			<key>Text</key>
+			<dict>
+				<key>Text</key>
+				<string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs28 \cf0 ack 2}</string>
+			</dict>
+			<key>Wrap</key>
+			<string>NO</string>
+		</dict>
+		<dict>
+			<key>Bounds</key>
+			<string>{{290.74178999999998, 239.21059}, {57, 27}}</string>
+			<key>Class</key>
+			<string>ShapedGraphic</string>
+			<key>FitText</key>
+			<string>YES</string>
+			<key>Flow</key>
+			<string>Resize</string>
+			<key>ID</key>
+			<integer>217</integer>
+			<key>Rotation</key>
+			<real>23</real>
+			<key>Shape</key>
+			<string>Rectangle</string>
+			<key>Style</key>
+			<dict>
+				<key>fill</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+				<key>shadow</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+				<key>stroke</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+			</dict>
+			<key>Text</key>
+			<dict>
+				<key>Text</key>
+				<string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs28 \cf0 no. 100}</string>
+			</dict>
+			<key>Wrap</key>
+			<string>NO</string>
+		</dict>
+		<dict>
+			<key>Bounds</key>
+			<string>{{342.63623000000001, 185.82861}, {38, 27}}</string>
+			<key>Class</key>
+			<string>ShapedGraphic</string>
+			<key>FitText</key>
+			<string>YES</string>
+			<key>Flow</key>
+			<string>Resize</string>
+			<key>ID</key>
+			<integer>216</integer>
+			<key>Rotation</key>
+			<real>18</real>
+			<key>Shape</key>
+			<string>Rectangle</string>
+			<key>Style</key>
+			<dict>
+				<key>fill</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+				<key>shadow</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+				<key>stroke</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+			</dict>
+			<key>Text</key>
+			<dict>
+				<key>Text</key>
+				<string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs28 \cf0 no...}</string>
+			</dict>
+			<key>Wrap</key>
+			<string>NO</string>
+		</dict>
+		<dict>
+			<key>Bounds</key>
+			<string>{{361.60431, 234}, {44, 27}}</string>
+			<key>Class</key>
+			<string>ShapedGraphic</string>
+			<key>FitText</key>
+			<string>YES</string>
+			<key>Flow</key>
+			<string>Resize</string>
+			<key>FontInfo</key>
+			<dict>
+				<key>Font</key>
+				<string>Helvetica</string>
+				<key>Size</key>
+				<real>14</real>
+			</dict>
+			<key>ID</key>
+			<integer>209</integer>
+			<key>Rotation</key>
+			<real>341</real>
+			<key>Shape</key>
+			<string>Rectangle</string>
+			<key>Style</key>
+			<dict>
+				<key>fill</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+				<key>shadow</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+				<key>stroke</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+			</dict>
+			<key>Text</key>
+			<dict>
+				<key>Text</key>
+				<string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs28 \cf0 ack 1}</string>
+			</dict>
+			<key>Wrap</key>
+			<string>NO</string>
+		</dict>
+		<dict>
+			<key>Bounds</key>
+			<string>{{351.16005999999999, 153.43960999999999}, {42, 27}}</string>
+			<key>Class</key>
+			<string>ShapedGraphic</string>
+			<key>FitText</key>
+			<string>YES</string>
+			<key>Flow</key>
+			<string>Resize</string>
+			<key>ID</key>
+			<integer>172</integer>
+			<key>Rotation</key>
+			<real>18</real>
+			<key>Shape</key>
+			<string>Rectangle</string>
+			<key>Style</key>
+			<dict>
+				<key>fill</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+				<key>shadow</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+				<key>stroke</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+			</dict>
+			<key>Text</key>
+			<dict>
+				<key>Text</key>
+				<string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs28 \cf0 no. 2}</string>
+			</dict>
+			<key>Wrap</key>
+			<string>NO</string>
+		</dict>
+		<dict>
+			<key>Bounds</key>
+			<string>{{363, 117}, {42, 27}}</string>
+			<key>Class</key>
+			<string>ShapedGraphic</string>
+			<key>FitText</key>
+			<string>YES</string>
+			<key>Flow</key>
+			<string>Resize</string>
+			<key>ID</key>
+			<integer>171</integer>
+			<key>Rotation</key>
+			<real>18</real>
+			<key>Shape</key>
+			<string>Rectangle</string>
+			<key>Style</key>
+			<dict>
+				<key>fill</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+				<key>shadow</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+				<key>stroke</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+			</dict>
+			<key>Text</key>
+			<dict>
+				<key>Text</key>
+				<string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf400
+\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs28 \cf0 no. 1}</string>
+			</dict>
+			<key>Wrap</key>
+			<string>NO</string>
+		</dict>
+		<dict>
+			<key>Class</key>
+			<string>LineGraphic</string>
+			<key>ID</key>
+			<integer>169</integer>
+			<key>Points</key>
+			<array>
+				<string>{504, 200.62189000000001}</string>
+				<string>{288, 312.62189000000001}</string>
+			</array>
+			<key>Style</key>
+			<dict>
+				<key>stroke</key>
+				<dict>
+					<key>Color</key>
+					<dict>
+						<key>b</key>
+						<string>0.934433</string>
+						<key>g</key>
+						<string>0</string>
+						<key>r</key>
+						<string>0.122713</string>
+					</dict>
+					<key>HeadArrow</key>
+					<string>FilledArrow</string>
+					<key>Legacy</key>
+					<true/>
+					<key>TailArrow</key>
+					<string>0</string>
+				</dict>
+			</dict>
+		</dict>
+		<dict>
+			<key>Class</key>
+			<string>LineGraphic</string>
+			<key>ID</key>
+			<integer>168</integer>
+			<key>Points</key>
+			<array>
+				<string>{504, 241.00763000000001}</string>
+				<string>{288, 353.00763000000001}</string>
+			</array>
+			<key>Style</key>
+			<dict>
+				<key>stroke</key>
+				<dict>
+					<key>Color</key>
+					<dict>
+						<key>b</key>
+						<string>0.934433</string>
+						<key>g</key>
+						<string>0</string>
+						<key>r</key>
+						<string>0.122713</string>
+					</dict>
+					<key>HeadArrow</key>
+					<string>FilledArrow</string>
+					<key>Legacy</key>
+					<true/>
+					<key>TailArrow</key>
+					<string>0</string>
+				</dict>
+			</dict>
+		</dict>
+		<dict>
+			<key>Class</key>
+			<string>LineGraphic</string>
+			<key>ID</key>
+			<integer>167</integer>
+			<key>Points</key>
+			<array>
+				<string>{504, 279}</string>
+				<string>{288, 391}</string>
+			</array>
+			<key>Style</key>
+			<dict>
+				<key>stroke</key>
+				<dict>
+					<key>Color</key>
+					<dict>
+						<key>b</key>
+						<string>0.934433</string>
+						<key>g</key>
+						<string>0</string>
+						<key>r</key>
+						<string>0.122713</string>
+					</dict>
+					<key>HeadArrow</key>
+					<string>FilledArrow</string>
+					<key>Legacy</key>
+					<true/>
+					<key>TailArrow</key>
+					<string>0</string>
+				</dict>
+			</dict>
+		</dict>
+		<dict>
+			<key>Class</key>
+			<string>LineGraphic</string>
+			<key>ID</key>
+			<integer>165</integer>
+			<key>Points</key>
+			<array>
+				<string>{289, 391}</string>
+				<string>{505, 492}</string>
+			</array>
+			<key>Style</key>
+			<dict>
+				<key>stroke</key>
+				<dict>
+					<key>Color</key>
+					<dict>
+						<key>b</key>
+						<string>0.934433</string>
+						<key>g</key>
+						<string>0</string>
+						<key>r</key>
+						<string>0.122713</string>
+					</dict>
+					<key>HeadArrow</key>
+					<string>FilledArrow</string>
+					<key>Legacy</key>
+					<true/>
+					<key>TailArrow</key>
+					<string>0</string>
+				</dict>
+			</dict>
+		</dict>
+		<dict>
+			<key>Class</key>
+			<string>LineGraphic</string>
+			<key>ID</key>
+			<integer>164</integer>
+			<key>Points</key>
+			<array>
+				<string>{288, 353}</string>
+				<string>{504, 454}</string>
+			</array>
+			<key>Style</key>
+			<dict>
+				<key>stroke</key>
+				<dict>
+					<key>Color</key>
+					<dict>
+						<key>b</key>
+						<string>0.934433</string>
+						<key>g</key>
+						<string>0</string>
+						<key>r</key>
+						<string>0.122713</string>
+					</dict>
+					<key>HeadArrow</key>
+					<string>FilledArrow</string>
+					<key>Legacy</key>
+					<true/>
+					<key>TailArrow</key>
+					<string>0</string>
+				</dict>
+			</dict>
+		</dict>
+		<dict>
+			<key>Class</key>
+			<string>LineGraphic</string>
+			<key>ID</key>
+			<integer>163</integer>
+			<key>Points</key>
+			<array>
+				<string>{288, 313}</string>
+				<string>{504, 414}</string>
+			</array>
+			<key>Style</key>
+			<dict>
+				<key>stroke</key>
+				<dict>
+					<key>Color</key>
+					<dict>
+						<key>b</key>
+						<string>0.934433</string>
+						<key>g</key>
+						<string>0</string>
+						<key>r</key>
+						<string>0.122713</string>
+					</dict>
+					<key>HeadArrow</key>
+					<string>FilledArrow</string>
+					<key>Legacy</key>
+					<true/>
+					<key>TailArrow</key>
+					<string>0</string>
+				</dict>
+			</dict>
+		</dict>
+		<dict>
+			<key>Class</key>
+			<string>LineGraphic</string>
+			<key>ID</key>
+			<integer>162</integer>
+			<key>Points</key>
+			<array>
+				<string>{288, 180}</string>
+				<string>{504, 281}</string>
+			</array>
+			<key>Style</key>
+			<dict>
+				<key>stroke</key>
+				<dict>
+					<key>Color</key>
+					<dict>
+						<key>b</key>
+						<string>0.934433</string>
+						<key>g</key>
+						<string>0</string>
+						<key>r</key>
+						<string>0.122713</string>
+					</dict>
+					<key>HeadArrow</key>
+					<string>FilledArrow</string>
+					<key>Legacy</key>
+					<true/>
+					<key>TailArrow</key>
+					<string>0</string>
+				</dict>
+			</dict>
+		</dict>
+		<dict>
+			<key>Class</key>
+			<string>LineGraphic</string>
+			<key>ID</key>
+			<integer>161</integer>
+			<key>Points</key>
+			<array>
+				<string>{288, 252}</string>
+				<string>{504, 353}</string>
+			</array>
+			<key>Style</key>
+			<dict>
+				<key>stroke</key>
+				<dict>
+					<key>Color</key>
+					<dict>
+						<key>b</key>
+						<string>0.934433</string>
+						<key>g</key>
+						<string>0</string>
+						<key>r</key>
+						<string>0.122713</string>
+					</dict>
+					<key>HeadArrow</key>
+					<string>FilledArrow</string>
+					<key>Legacy</key>
+					<true/>
+					<key>TailArrow</key>
+					<string>0</string>
+				</dict>
+			</dict>
+		</dict>
+		<dict>
+			<key>Class</key>
+			<string>LineGraphic</string>
+			<key>ID</key>
+			<integer>160</integer>
+			<key>Points</key>
+			<array>
+				<string>{288, 139.5}</string>
+				<string>{504, 240.5}</string>
+			</array>
+			<key>Style</key>
+			<dict>
+				<key>stroke</key>
+				<dict>
+					<key>Color</key>
+					<dict>
+						<key>b</key>
+						<string>0.934433</string>
+						<key>g</key>
+						<string>0</string>
+						<key>r</key>
+						<string>0.122713</string>
+					</dict>
+					<key>HeadArrow</key>
+					<string>FilledArrow</string>
+					<key>Legacy</key>
+					<true/>
+					<key>TailArrow</key>
+					<string>0</string>
+				</dict>
+			</dict>
+		</dict>
+		<dict>
+			<key>Class</key>
+			<string>LineGraphic</string>
+			<key>Head</key>
+			<dict>
+				<key>ID</key>
+				<integer>158</integer>
+				<key>Position</key>
+				<real>0.29398149251937866</real>
+			</dict>
+			<key>ID</key>
+			<integer>159</integer>
+			<key>Points</key>
+			<array>
+				<string>{288, 98.000000596046448}</string>
+				<string>{504, 199.00000476837158}</string>
+			</array>
+			<key>Style</key>
+			<dict>
+				<key>stroke</key>
+				<dict>
+					<key>Color</key>
+					<dict>
+						<key>b</key>
+						<string>0.934433</string>
+						<key>g</key>
+						<string>0</string>
+						<key>r</key>
+						<string>0.122713</string>
+					</dict>
+					<key>HeadArrow</key>
+					<string>FilledArrow</string>
+					<key>Legacy</key>
+					<true/>
+					<key>TailArrow</key>
+					<string>0</string>
+				</dict>
+			</dict>
+			<key>Tail</key>
+			<dict>
+				<key>ID</key>
+				<integer>157</integer>
+				<key>Position</key>
+				<real>0.060185186564922333</real>
+			</dict>
+		</dict>
+		<dict>
+			<key>Class</key>
+			<string>LineGraphic</string>
+			<key>ID</key>
+			<integer>158</integer>
+			<key>Points</key>
+			<array>
+				<string>{504, 72}</string>
+				<string>{504, 504}</string>
+			</array>
+			<key>Style</key>
+			<dict>
+				<key>stroke</key>
+				<dict>
+					<key>HeadArrow</key>
+					<string>0</string>
+					<key>Legacy</key>
+					<true/>
+					<key>TailArrow</key>
+					<string>0</string>
+				</dict>
+			</dict>
+		</dict>
+		<dict>
+			<key>Class</key>
+			<string>LineGraphic</string>
+			<key>ID</key>
+			<integer>157</integer>
+			<key>Points</key>
+			<array>
+				<string>{288, 72}</string>
+				<string>{288, 504}</string>
+			</array>
+			<key>Style</key>
+			<dict>
+				<key>stroke</key>
+				<dict>
+					<key>HeadArrow</key>
+					<string>0</string>
+					<key>Legacy</key>
+					<true/>
+					<key>TailArrow</key>
+					<string>0</string>
+				</dict>
+			</dict>
+		</dict>
+	</array>
+	<key>GridInfo</key>
+	<dict>
+		<key>ShowsGrid</key>
+		<string>YES</string>
+	</dict>
+	<key>GuidesLocked</key>
+	<string>NO</string>
+	<key>GuidesVisible</key>
+	<string>YES</string>
+	<key>HPages</key>
+	<integer>1</integer>
+	<key>ImageCounter</key>
+	<integer>1</integer>
+	<key>KeepToScale</key>
+	<false/>
+	<key>Layers</key>
+	<array>
+		<dict>
+			<key>Lock</key>
+			<string>NO</string>
+			<key>Name</key>
+			<string>Layer 1</string>
+			<key>Print</key>
+			<string>YES</string>
+			<key>View</key>
+			<string>YES</string>
+		</dict>
+	</array>
+	<key>LayoutInfo</key>
+	<dict>
+		<key>Animate</key>
+		<string>NO</string>
+		<key>circoMinDist</key>
+		<real>18</real>
+		<key>circoSeparation</key>
+		<real>0.0</real>
+		<key>layoutEngine</key>
+		<string>dot</string>
+		<key>neatoSeparation</key>
+		<real>0.0</real>
+		<key>twopiSeparation</key>
+		<real>0.0</real>
+	</dict>
+	<key>LinksVisible</key>
+	<string>NO</string>
+	<key>MagnetsVisible</key>
+	<string>NO</string>
+	<key>MasterSheets</key>
+	<array/>
+	<key>ModificationDate</key>
+	<string>2014-01-22 22:42:38 +0000</string>
+	<key>Modifier</key>
+	<string>Katie McCormick</string>
+	<key>NotesVisible</key>
+	<string>NO</string>
+	<key>Orientation</key>
+	<integer>2</integer>
+	<key>OriginVisible</key>
+	<string>NO</string>
+	<key>PageBreaks</key>
+	<string>YES</string>
+	<key>PrintInfo</key>
+	<dict>
+		<key>NSBottomMargin</key>
+		<array>
+			<string>float</string>
+			<string>41</string>
+		</array>
+		<key>NSHorizonalPagination</key>
+		<array>
+			<string>int</string>
+			<string>0</string>
+		</array>
+		<key>NSLeftMargin</key>
+		<array>
+			<string>float</string>
+			<string>18</string>
+		</array>
+		<key>NSPaperSize</key>
+		<array>
+			<string>size</string>
+			<string>{612.00002479553223, 792}</string>
+		</array>
+		<key>NSPrintReverseOrientation</key>
+		<array>
+			<string>int</string>
+			<string>0</string>
+		</array>
+		<key>NSRightMargin</key>
+		<array>
+			<string>float</string>
+			<string>18</string>
+		</array>
+		<key>NSTopMargin</key>
+		<array>
+			<string>float</string>
+			<string>18</string>
+		</array>
+	</dict>
+	<key>PrintOnePage</key>
+	<false/>
+	<key>ReadOnly</key>
+	<string>NO</string>
+	<key>RowAlign</key>
+	<integer>1</integer>
+	<key>RowSpacing</key>
+	<real>36</real>
+	<key>SheetTitle</key>
+	<string>Canvas 1</string>
+	<key>SmartAlignmentGuidesActive</key>
+	<string>YES</string>
+	<key>SmartDistanceGuidesActive</key>
+	<string>YES</string>
+	<key>UniqueID</key>
+	<integer>1</integer>
+	<key>UseEntirePage</key>
+	<false/>
+	<key>VPages</key>
+	<integer>1</integer>
+	<key>WindowInfo</key>
+	<dict>
+		<key>CurrentSheet</key>
+		<integer>0</integer>
+		<key>ExpandedCanvases</key>
+		<array>
+			<dict>
+				<key>name</key>
+				<string>Canvas 1</string>
+			</dict>
+		</array>
+		<key>Frame</key>
+		<string>{{170, 139}, {1218, 882}}</string>
+		<key>ListView</key>
+		<true/>
+		<key>OutlineWidth</key>
+		<integer>142</integer>
+		<key>RightSidebar</key>
+		<false/>
+		<key>ShowRuler</key>
+		<true/>
+		<key>Sidebar</key>
+		<true/>
+		<key>SidebarWidth</key>
+		<integer>120</integer>
+		<key>VisibleRegion</key>
+		<string>{{40.5, 0}, {534.5, 364}}</string>
+		<key>Zoom</key>
+		<real>2</real>
+		<key>ZoomValues</key>
+		<array>
+			<array>
+				<string>Canvas 1</string>
+				<real>2</real>
+				<real>1</real>
+			</array>
+		</array>
+	</dict>
+</dict>
+</plist>
diff --git a/docs/image_sources/mediarouter/media-route-provider-framework.graffle/._data.plist b/docs/image_sources/mediarouter/media-route-provider-framework.graffle/._data.plist
new file mode 100644
index 0000000..d82ea05
--- /dev/null
+++ b/docs/image_sources/mediarouter/media-route-provider-framework.graffle/._data.plist
Binary files differ
diff --git a/docs/image_sources/mediarouter/media-route-provider-framework.graffle/._image1.png b/docs/image_sources/mediarouter/media-route-provider-framework.graffle/._image1.png
new file mode 100644
index 0000000..3435e35
--- /dev/null
+++ b/docs/image_sources/mediarouter/media-route-provider-framework.graffle/._image1.png
Binary files differ
diff --git a/docs/image_sources/mediarouter/media-route-provider-framework.graffle/data.plist b/docs/image_sources/mediarouter/media-route-provider-framework.graffle/data.plist
new file mode 100644
index 0000000..07791df
--- /dev/null
+++ b/docs/image_sources/mediarouter/media-route-provider-framework.graffle/data.plist
Binary files differ
diff --git a/docs/image_sources/mediarouter/media-route-provider-framework.graffle/image1.png b/docs/image_sources/mediarouter/media-route-provider-framework.graffle/image1.png
new file mode 100644
index 0000000..d6e3e95
--- /dev/null
+++ b/docs/image_sources/mediarouter/media-route-provider-framework.graffle/image1.png
Binary files differ
diff --git a/docs/image_sources/mediarouter/media-router-framework.graffle/data.plist b/docs/image_sources/mediarouter/media-router-framework.graffle/data.plist
new file mode 100644
index 0000000..ffd8212
--- /dev/null
+++ b/docs/image_sources/mediarouter/media-router-framework.graffle/data.plist
Binary files differ
diff --git a/docs/image_sources/mediarouter/media-router-framework.graffle/image1.png b/docs/image_sources/mediarouter/media-router-framework.graffle/image1.png
new file mode 100644
index 0000000..d6e3e95
--- /dev/null
+++ b/docs/image_sources/mediarouter/media-router-framework.graffle/image1.png
Binary files differ
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index b8911d4..9b71d64 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -1042,7 +1042,7 @@
      * <p>This method will not affect the behavior of a bitmap without an alpha
      * channel, or if {@link #hasAlpha()} returns false.</p>
      *
-     * <p>Calling createBitmap() or createScaledBitmap() with a source
+     * <p>Calling {@link #createBitmap} or {@link #createScaledBitmap} with a source
      * Bitmap whose colors are not pre-multiplied may result in a RuntimeException,
      * since those functions require drawing the source, which is not supported for
      * un-pre-multiplied Bitmaps.</p>
@@ -1624,7 +1624,7 @@
 
     private static native void nativePrepareToDraw(long nativeBitmap);
     private static native boolean nativeHasAlpha(long nativeBitmap);
-    private static native void nativeSetAlphaAndPremultiplied(long nativeBitmap, boolean hasAlpha,
+    private static native void nativeSetAlphaAndPremultiplied(long nBitmap, boolean hasAlpha,
                                                               boolean isPremul);
     private static native boolean nativeHasMipMap(long nativeBitmap);
     private static native void nativeSetHasMipMap(long nativeBitmap, boolean hasMipMap);
diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java
index 81cc11b..2ea9b8e 100644
--- a/graphics/java/android/graphics/drawable/LayerDrawable.java
+++ b/graphics/java/android/graphics/drawable/LayerDrawable.java
@@ -295,6 +295,7 @@
                     drawable.setCallback(this);
                 }
                 layers[i].mDrawable = drawable;
+                mLayerState.mHaveStateful = false;
                 return true;
             }
         }
diff --git a/graphics/java/android/renderscript/ScriptIntrinsicResize.java b/graphics/java/android/renderscript/ScriptIntrinsicResize.java
new file mode 100644
index 0000000..a42d3be
--- /dev/null
+++ b/graphics/java/android/renderscript/ScriptIntrinsicResize.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.renderscript;
+
+/**
+ * Intrinsic for performing a resize of a 2D allocation.
+ */
+public final class ScriptIntrinsicResize extends ScriptIntrinsic {
+    private Allocation mInput;
+
+    private ScriptIntrinsicResize(int id, RenderScript rs) {
+        super(id, rs);
+    }
+
+    /**
+     * Supported elements types are {@link Element#U8}, {@link
+     * Element#U8_2}, {@link Element#U8_3}, {@link Element#U8_4}
+     *
+     * @param rs The RenderScript context
+     *
+     * @return ScriptIntrinsicResize
+     */
+    public static ScriptIntrinsicResize create(RenderScript rs) {
+        int id = rs.nScriptIntrinsicCreate(12, 0);
+        ScriptIntrinsicResize si = new ScriptIntrinsicResize(id, rs);
+        return si;
+
+    }
+
+    /**
+     * Set the input of the resize.
+     * Must match the element type supplied during create.
+     *
+     * @param ain The input allocation.
+     */
+    public void setInput(Allocation ain) {
+        Element e = ain.getElement();
+        if (!e.isCompatible(Element.U8(mRS)) &&
+            !e.isCompatible(Element.U8_2(mRS)) &&
+            !e.isCompatible(Element.U8_3(mRS)) &&
+            !e.isCompatible(Element.U8_4(mRS))) {
+            throw new RSIllegalArgumentException("Unsuported element type.");
+        }
+
+        mInput = ain;
+        setVar(0, ain);
+    }
+
+    /**
+     * Get a FieldID for the input field of this intrinsic.
+     *
+     * @return Script.FieldID The FieldID object.
+     */
+    public Script.FieldID getFieldID_Input() {
+        return createFieldID(0, null);
+    }
+
+
+    /**
+     * Resize copy the input allocation to the output specified. The
+     * Allocation is rescaled if necessary using bi-cubic
+     * interpolation.
+     *
+     * @param aout Output allocation. Element type must match
+     *             current input.  Must not be same as input.
+     */
+    public void forEach_bicubic(Allocation aout) {
+        if (aout == mInput) {
+            throw new RSIllegalArgumentException("Output cannot be same as Input.");
+        }
+        forEach_bicubic(aout, null);
+    }
+
+    /**
+     * Resize copy the input allocation to the output specified. The
+     * Allocation is rescaled if necessary using bi-cubic
+     * interpolation.
+     *
+     * @param aout Output allocation. Element type must match
+     *             current input.
+     * @param opt LaunchOptions for clipping
+     */
+    public void forEach_bicubic(Allocation aout, Script.LaunchOptions opt) {
+        forEach(0, null, aout, null, opt);
+    }
+
+    /**
+     * Get a KernelID for this intrinsic kernel.
+     *
+     * @return Script.KernelID The KernelID object.
+     */
+    public Script.KernelID getKernelID_bicubic() {
+        return createKernelID(0, 2, null, null);
+    }
+
+
+}
+
diff --git a/include/androidfw/ResourceTypes.h b/include/androidfw/ResourceTypes.h
index b334aab..2306a7a 100644
--- a/include/androidfw/ResourceTypes.h
+++ b/include/androidfw/ResourceTypes.h
@@ -1044,6 +1044,7 @@
         UI_MODE_TYPE_CAR = ACONFIGURATION_UI_MODE_TYPE_CAR,
         UI_MODE_TYPE_TELEVISION = ACONFIGURATION_UI_MODE_TYPE_TELEVISION,
         UI_MODE_TYPE_APPLIANCE = ACONFIGURATION_UI_MODE_TYPE_APPLIANCE,
+        UI_MODE_TYPE_WATCH = ACONFIGURATION_UI_MODE_TYPE_WATCH,
 
         // uiMode bits for the night switch.
         MASK_UI_MODE_NIGHT = 0x30,
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 1ffe665..9e59a13 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -2517,6 +2517,9 @@
             case ResTable_config::UI_MODE_TYPE_APPLIANCE:
                 res.append("appliance");
                 break;
+            case ResTable_config::UI_MODE_TYPE_WATCH:
+                res.append("watch");
+                break;
             default:
                 res.appendFormat("uiModeType=%d",
                         dtohs(screenLayout&ResTable_config::MASK_UI_MODE_TYPE));
diff --git a/services/common_time/Android.mk b/libs/common_time/Android.mk
similarity index 100%
rename from services/common_time/Android.mk
rename to libs/common_time/Android.mk
diff --git a/services/common_time/clock_recovery.cpp b/libs/common_time/clock_recovery.cpp
similarity index 100%
rename from services/common_time/clock_recovery.cpp
rename to libs/common_time/clock_recovery.cpp
diff --git a/services/common_time/clock_recovery.h b/libs/common_time/clock_recovery.h
similarity index 100%
rename from services/common_time/clock_recovery.h
rename to libs/common_time/clock_recovery.h
diff --git a/services/common_time/common_clock.cpp b/libs/common_time/common_clock.cpp
similarity index 100%
rename from services/common_time/common_clock.cpp
rename to libs/common_time/common_clock.cpp
diff --git a/services/common_time/common_clock.h b/libs/common_time/common_clock.h
similarity index 100%
rename from services/common_time/common_clock.h
rename to libs/common_time/common_clock.h
diff --git a/services/common_time/common_clock_service.cpp b/libs/common_time/common_clock_service.cpp
similarity index 100%
rename from services/common_time/common_clock_service.cpp
rename to libs/common_time/common_clock_service.cpp
diff --git a/services/common_time/common_clock_service.h b/libs/common_time/common_clock_service.h
similarity index 100%
rename from services/common_time/common_clock_service.h
rename to libs/common_time/common_clock_service.h
diff --git a/services/common_time/common_time_config_service.cpp b/libs/common_time/common_time_config_service.cpp
similarity index 100%
rename from services/common_time/common_time_config_service.cpp
rename to libs/common_time/common_time_config_service.cpp
diff --git a/services/common_time/common_time_config_service.h b/libs/common_time/common_time_config_service.h
similarity index 100%
rename from services/common_time/common_time_config_service.h
rename to libs/common_time/common_time_config_service.h
diff --git a/services/common_time/common_time_server.cpp b/libs/common_time/common_time_server.cpp
similarity index 100%
rename from services/common_time/common_time_server.cpp
rename to libs/common_time/common_time_server.cpp
diff --git a/services/common_time/common_time_server.h b/libs/common_time/common_time_server.h
similarity index 100%
rename from services/common_time/common_time_server.h
rename to libs/common_time/common_time_server.h
diff --git a/services/common_time/common_time_server_api.cpp b/libs/common_time/common_time_server_api.cpp
similarity index 100%
rename from services/common_time/common_time_server_api.cpp
rename to libs/common_time/common_time_server_api.cpp
diff --git a/services/common_time/common_time_server_packets.cpp b/libs/common_time/common_time_server_packets.cpp
similarity index 100%
rename from services/common_time/common_time_server_packets.cpp
rename to libs/common_time/common_time_server_packets.cpp
diff --git a/services/common_time/common_time_server_packets.h b/libs/common_time/common_time_server_packets.h
similarity index 100%
rename from services/common_time/common_time_server_packets.h
rename to libs/common_time/common_time_server_packets.h
diff --git a/services/common_time/diag_thread.cpp b/libs/common_time/diag_thread.cpp
similarity index 100%
rename from services/common_time/diag_thread.cpp
rename to libs/common_time/diag_thread.cpp
diff --git a/services/common_time/diag_thread.h b/libs/common_time/diag_thread.h
similarity index 100%
rename from services/common_time/diag_thread.h
rename to libs/common_time/diag_thread.h
diff --git a/services/common_time/main.cpp b/libs/common_time/main.cpp
similarity index 100%
rename from services/common_time/main.cpp
rename to libs/common_time/main.cpp
diff --git a/services/common_time/utils.cpp b/libs/common_time/utils.cpp
similarity index 100%
rename from services/common_time/utils.cpp
rename to libs/common_time/utils.cpp
diff --git a/services/common_time/utils.h b/libs/common_time/utils.h
similarity index 100%
rename from services/common_time/utils.h
rename to libs/common_time/utils.h
diff --git a/libs/hwui/TextureCache.cpp b/libs/hwui/TextureCache.cpp
index d5ba8c3..a9ab2c6 100644
--- a/libs/hwui/TextureCache.cpp
+++ b/libs/hwui/TextureCache.cpp
@@ -184,7 +184,7 @@
     Mutex::Autolock _l(mLock);
     size_t count = mGarbage.size();
     for (size_t i = 0; i < count; i++) {
-        SkBitmap* bitmap = mGarbage.itemAt(i);
+        const SkBitmap* bitmap = mGarbage.itemAt(i);
         mCache.remove(bitmap);
         delete bitmap;
     }
diff --git a/libs/hwui/font/Font.cpp b/libs/hwui/font/Font.cpp
index 1d50bd5..d829f58 100644
--- a/libs/hwui/font/Font.cpp
+++ b/libs/hwui/font/Font.cpp
@@ -42,6 +42,7 @@
 
 Font::Font(FontRenderer* state, const Font::FontDescription& desc) :
         mState(state), mDescription(desc) {
+    mDeviceProperties = SkDeviceProperties::Make(SkDeviceProperties::Geometry::MakeDefault(), 1.0f);
 }
 
 Font::FontDescription::FontDescription(const SkPaint* paint, const mat4& matrix) {
@@ -282,7 +283,7 @@
     if (cachedGlyph) {
         // Is the glyph still in texture cache?
         if (!cachedGlyph->mIsValid) {
-            SkAutoGlyphCache autoCache(*paint, NULL, &mDescription.mLookupTransform);
+            SkAutoGlyphCache autoCache(*paint, &mDeviceProperties, &mDescription.mLookupTransform);
             const SkGlyph& skiaGlyph = GET_METRICS(autoCache.getCache(), textUnit);
             updateGlyphCache(paint, skiaGlyph, autoCache.getCache(), cachedGlyph, precaching);
         }
@@ -474,7 +475,7 @@
     CachedGlyphInfo* newGlyph = new CachedGlyphInfo();
     mCachedGlyphs.add(glyph, newGlyph);
 
-    SkAutoGlyphCache autoCache(*paint, NULL, &mDescription.mLookupTransform);
+    SkAutoGlyphCache autoCache(*paint, &mDeviceProperties, &mDescription.mLookupTransform);
     const SkGlyph& skiaGlyph = GET_METRICS(autoCache.getCache(), glyph);
     newGlyph->mIsValid = false;
     newGlyph->mGlyphIndex = skiaGlyph.fID;
diff --git a/libs/hwui/font/Font.h b/libs/hwui/font/Font.h
index f68b430..1e0e0c8 100644
--- a/libs/hwui/font/Font.h
+++ b/libs/hwui/font/Font.h
@@ -19,6 +19,8 @@
 
 #include <utils/KeyedVector.h>
 
+#include <SkScalar.h>
+#include <SkDeviceProperties.h>
 #include <SkGlyphCache.h>
 #include <SkScalerContext.h>
 #include <SkPaint.h>
@@ -145,6 +147,7 @@
     DefaultKeyedVector<glyph_t, CachedGlyphInfo*> mCachedGlyphs;
 
     bool mIdentityTransform;
+    SkDeviceProperties mDeviceProperties;
 };
 
 inline int strictly_order_type(const Font::FontDescription& lhs,
diff --git a/services/input/Android.mk b/libs/input/Android.mk
similarity index 100%
rename from services/input/Android.mk
rename to libs/input/Android.mk
diff --git a/services/input/EventHub.cpp b/libs/input/EventHub.cpp
similarity index 93%
rename from services/input/EventHub.cpp
rename to libs/input/EventHub.cpp
index e3a3e17..e30a772 100644
--- a/services/input/EventHub.cpp
+++ b/libs/input/EventHub.cpp
@@ -509,8 +509,9 @@
 bool EventHub::hasLed(int32_t deviceId, int32_t led) const {
     AutoMutex _l(mLock);
     Device* device = getDeviceLocked(deviceId);
-    if (device && led >= 0 && led <= LED_MAX) {
-        if (test_bit(led, device->ledBitmask)) {
+    int32_t sc;
+    if (device && mapLed(device, led, &sc) == NO_ERROR) {
+        if (test_bit(sc, device->ledBitmask)) {
             return true;
         }
     }
@@ -520,12 +521,17 @@
 void EventHub::setLedState(int32_t deviceId, int32_t led, bool on) {
     AutoMutex _l(mLock);
     Device* device = getDeviceLocked(deviceId);
-    if (device && !device->isVirtual() && led >= 0 && led <= LED_MAX) {
+    setLedStateLocked(device, led, on);
+}
+
+void EventHub::setLedStateLocked(Device* device, int32_t led, bool on) {
+    int32_t sc;
+    if (device && !device->isVirtual() && mapLed(device, led, &sc) != NAME_NOT_FOUND) {
         struct input_event ev;
         ev.time.tv_sec = 0;
         ev.time.tv_usec = 0;
         ev.type = EV_LED;
-        ev.code = led;
+        ev.code = sc;
         ev.value = on ? 1 : 0;
 
         ssize_t nWrite;
@@ -570,6 +576,57 @@
     return false;
 }
 
+static String8 generateDescriptor(InputDeviceIdentifier& identifier) {
+    String8 rawDescriptor;
+    rawDescriptor.appendFormat(":%04x:%04x:", identifier.vendor,
+            identifier.product);
+    // TODO add handling for USB devices to not uniqueify kbs that show up twice
+    if (!identifier.uniqueId.isEmpty()) {
+        rawDescriptor.append("uniqueId:");
+        rawDescriptor.append(identifier.uniqueId);
+    } else if (identifier.nonce != 0) {
+        rawDescriptor.appendFormat("nonce:%04x", identifier.nonce);
+    }
+
+    if (identifier.vendor == 0 && identifier.product == 0) {
+        // If we don't know the vendor and product id, then the device is probably
+        // built-in so we need to rely on other information to uniquely identify
+        // the input device.  Usually we try to avoid relying on the device name or
+        // location but for built-in input device, they are unlikely to ever change.
+        if (!identifier.name.isEmpty()) {
+            rawDescriptor.append("name:");
+            rawDescriptor.append(identifier.name);
+        } else if (!identifier.location.isEmpty()) {
+            rawDescriptor.append("location:");
+            rawDescriptor.append(identifier.location);
+        }
+    }
+    identifier.descriptor = sha1(rawDescriptor);
+    return rawDescriptor;
+}
+
+void EventHub::assignDescriptorLocked(InputDeviceIdentifier& identifier) {
+    // Compute a device descriptor that uniquely identifies the device.
+    // The descriptor is assumed to be a stable identifier.  Its value should not
+    // change between reboots, reconnections, firmware updates or new releases
+    // of Android. In practice we sometimes get devices that cannot be uniquely
+    // identified. In this case we enforce uniqueness between connected devices.
+    // Ideally, we also want the descriptor to be short and relatively opaque.
+
+    identifier.nonce = 0;
+    String8 rawDescriptor = generateDescriptor(identifier);
+    if (identifier.uniqueId.isEmpty()) {
+        // If it didn't have a unique id check for conflicts and enforce
+        // uniqueness if necessary.
+        while(getDeviceByDescriptorLocked(identifier.descriptor) != NULL) {
+            identifier.nonce++;
+            rawDescriptor = generateDescriptor(identifier);
+        }
+    }
+    ALOGV("Created descriptor: raw=%s, cooked=%s", rawDescriptor.string(),
+            identifier.descriptor.string());
+}
+
 void EventHub::vibrate(int32_t deviceId, nsecs_t duration) {
     AutoMutex _l(mLock);
     Device* device = getDeviceLocked(deviceId);
@@ -626,6 +683,17 @@
     }
 }
 
+EventHub::Device* EventHub::getDeviceByDescriptorLocked(String8& descriptor) const {
+    size_t size = mDevices.size();
+    for (size_t i = 0; i < size; i++) {
+        Device* device = mDevices.valueAt(i);
+        if (descriptor.compare(device->identifier.descriptor) == 0) {
+            return device;
+        }
+    }
+    return NULL;
+}
+
 EventHub::Device* EventHub::getDeviceLocked(int32_t deviceId) const {
     if (deviceId == BUILT_IN_KEYBOARD_ID) {
         deviceId = mBuiltInKeyboardId;
@@ -991,10 +1059,6 @@
         AKEYCODE_BUTTON_L2, AKEYCODE_BUTTON_R2,
         AKEYCODE_BUTTON_THUMBL, AKEYCODE_BUTTON_THUMBR,
         AKEYCODE_BUTTON_START, AKEYCODE_BUTTON_SELECT, AKEYCODE_BUTTON_MODE,
-        AKEYCODE_BUTTON_1, AKEYCODE_BUTTON_2, AKEYCODE_BUTTON_3, AKEYCODE_BUTTON_4,
-        AKEYCODE_BUTTON_5, AKEYCODE_BUTTON_6, AKEYCODE_BUTTON_7, AKEYCODE_BUTTON_8,
-        AKEYCODE_BUTTON_9, AKEYCODE_BUTTON_10, AKEYCODE_BUTTON_11, AKEYCODE_BUTTON_12,
-        AKEYCODE_BUTTON_13, AKEYCODE_BUTTON_14, AKEYCODE_BUTTON_15, AKEYCODE_BUTTON_16,
 };
 
 status_t EventHub::openDeviceLocked(const char *devicePath) {
@@ -1065,7 +1129,7 @@
     }
 
     // Fill in the descriptor.
-    setDescriptor(identifier);
+    assignDescriptorLocked(identifier);
 
     // Make file descriptor non-blocking for use with poll().
     if (fcntl(fd, F_SETFL, O_NONBLOCK)) {
@@ -1237,8 +1301,10 @@
         device->classes |= INPUT_DEVICE_CLASS_EXTERNAL;
     }
 
-    if (device->classes & (INPUT_DEVICE_CLASS_JOYSTICK | INPUT_DEVICE_CLASS_GAMEPAD)) {
+    if (device->classes & (INPUT_DEVICE_CLASS_JOYSTICK | INPUT_DEVICE_CLASS_DPAD)
+            && device->classes & INPUT_DEVICE_CLASS_GAMEPAD) {
         device->controllerNumber = getNextControllerNumberLocked(device);
+        setLedForController(device);
     }
 
     // Register with epoll.
@@ -1299,7 +1365,7 @@
     InputDeviceIdentifier identifier;
     identifier.name = "Virtual";
     identifier.uniqueId = "<virtual>";
-    setDescriptor(identifier);
+    assignDescriptorLocked(identifier);
 
     Device* device = new Device(-1, VIRTUAL_KEYBOARD_ID, String8("<virtual>"), identifier);
     device->classes = INPUT_DEVICE_CLASS_KEYBOARD
@@ -1378,6 +1444,11 @@
     mControllerNumbers.clearBit(static_cast<uint32_t>(num - 1));
 }
 
+void EventHub::setLedForController(Device* device) {
+    for (int i = 0; i < MAX_CONTROLLER_LEDS; i++) {
+        setLedStateLocked(device, ALED_CONTROLLER_1 + i, device->controllerNumber == i + 1);
+    }
+}
 
 bool EventHub::hasKeycodeLocked(Device* device, int keycode) const {
     if (!device->keyMap.haveKeyLayout() || !device->keyBitmask) {
@@ -1397,6 +1468,21 @@
     return false;
 }
 
+status_t EventHub::mapLed(Device* device, int32_t led, int32_t* outScanCode) const {
+    if (!device->keyMap.haveKeyLayout() || !device->ledBitmask) {
+        return NAME_NOT_FOUND;
+    }
+
+    int32_t scanCode;
+    if(device->keyMap.keyLayoutMap->findScanCodeForLed(led, &scanCode) != NAME_NOT_FOUND) {
+        if(scanCode >= 0 && scanCode <= LED_MAX && test_bit(scanCode, device->ledBitmask)) {
+            *outScanCode = scanCode;
+            return NO_ERROR;
+        }
+    }
+    return NAME_NOT_FOUND;
+}
+
 status_t EventHub::closeDeviceByPathLocked(const char *devicePath) {
     Device* device = getDeviceByPathLocked(devicePath);
     if (device) {
diff --git a/services/input/EventHub.h b/libs/input/EventHub.h
similarity index 97%
rename from services/input/EventHub.h
rename to libs/input/EventHub.h
index ae28f01..86c05af 100644
--- a/services/input/EventHub.h
+++ b/libs/input/EventHub.h
@@ -231,6 +231,8 @@
             uint8_t* outFlags) const = 0;
 
     virtual bool hasScanCode(int32_t deviceId, int32_t scanCode) const = 0;
+
+    /* LED related functions expect Android LED constants, not scan codes or HID usages */
     virtual bool hasLed(int32_t deviceId, int32_t led) const = 0;
     virtual void setLedState(int32_t deviceId, int32_t led, bool on) = 0;
 
@@ -371,6 +373,7 @@
     status_t openDeviceLocked(const char *devicePath);
     void createVirtualKeyboardLocked();
     void addDeviceLocked(Device* device);
+    void assignDescriptorLocked(InputDeviceIdentifier& identifier);
 
     status_t closeDeviceByPathLocked(const char *devicePath);
     void closeDeviceLocked(Device* device);
@@ -380,6 +383,7 @@
     void scanDevicesLocked();
     status_t readNotifyLocked();
 
+    Device* getDeviceByDescriptorLocked(String8& descriptor) const;
     Device* getDeviceLocked(int32_t deviceId) const;
     Device* getDeviceByPathLocked(const char* devicePath) const;
 
@@ -393,6 +397,10 @@
 
     int32_t getNextControllerNumberLocked(Device* device);
     void releaseControllerNumberLocked(Device* device);
+    void setLedForController(Device* device);
+
+    status_t mapLed(Device* device, int32_t led, int32_t* outScanCode) const;
+    void setLedStateLocked(Device* device, int32_t led, bool on);
 
     // Protect all internal state.
     mutable Mutex mLock;
diff --git a/services/input/InputApplication.cpp b/libs/input/InputApplication.cpp
similarity index 100%
rename from services/input/InputApplication.cpp
rename to libs/input/InputApplication.cpp
diff --git a/services/input/InputApplication.h b/libs/input/InputApplication.h
similarity index 100%
rename from services/input/InputApplication.h
rename to libs/input/InputApplication.h
diff --git a/services/input/InputDispatcher.cpp b/libs/input/InputDispatcher.cpp
similarity index 95%
rename from services/input/InputDispatcher.cpp
rename to libs/input/InputDispatcher.cpp
index 0da8489..f594df2 100644
--- a/services/input/InputDispatcher.cpp
+++ b/libs/input/InputDispatcher.cpp
@@ -248,10 +248,10 @@
 void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
     nsecs_t currentTime = now();
 
-    // Reset the key repeat timer whenever we disallow key events, even if the next event
-    // is not a key.  This is to ensure that we abort a key repeat if the device is just coming
-    // out of sleep.
-    if (!mPolicy->isKeyRepeatEnabled()) {
+    // Reset the key repeat timer whenever normal dispatch is suspended while the
+    // device is in a non-interactive state.  This is to ensure that we abort a key
+    // repeat if the device is just coming out of sleep.
+    if (!mDispatchEnabled) {
         resetKeyRepeatLocked();
     }
 
@@ -1020,7 +1020,14 @@
                 sp<InputWindowHandle> windowHandle = connection->inputWindowHandle;
 
                 if (windowHandle != NULL) {
-                    mTouchState.removeWindow(windowHandle);
+                    const InputWindowInfo* info = windowHandle->getInfo();
+                    if (info) {
+                        ssize_t stateIndex = mTouchStatesByDisplay.indexOfKey(info->displayId);
+                        if (stateIndex >= 0) {
+                            mTouchStatesByDisplay.editValueAt(stateIndex).removeWindow(
+                                    windowHandle);
+                        }
+                    }
                 }
 
                 if (connection->status == Connection::STATUS_NORMAL) {
@@ -1128,30 +1135,6 @@
 
     // For security reasons, we defer updating the touch state until we are sure that
     // event injection will be allowed.
-    //
-    // FIXME In the original code, screenWasOff could never be set to true.
-    //       The reason is that the POLICY_FLAG_WOKE_HERE
-    //       and POLICY_FLAG_BRIGHT_HERE flags were set only when preprocessing raw
-    //       EV_KEY, EV_REL and EV_ABS events.  As it happens, the touch event was
-    //       actually enqueued using the policyFlags that appeared in the final EV_SYN
-    //       events upon which no preprocessing took place.  So policyFlags was always 0.
-    //       In the new native input dispatcher we're a bit more careful about event
-    //       preprocessing so the touches we receive can actually have non-zero policyFlags.
-    //       Unfortunately we obtain undesirable behavior.
-    //
-    //       Here's what happens:
-    //
-    //       When the device dims in anticipation of going to sleep, touches
-    //       in windows which have FLAG_TOUCHABLE_WHEN_WAKING cause
-    //       the device to brighten and reset the user activity timer.
-    //       Touches on other windows (such as the launcher window)
-    //       are dropped.  Then after a moment, the device goes to sleep.  Oops.
-    //
-    //       Also notice how screenWasOff was being initialized using POLICY_FLAG_BRIGHT_HERE
-    //       instead of POLICY_FLAG_WOKE_HERE...
-    //
-    bool screenWasOff = false; // original policy: policyFlags & POLICY_FLAG_BRIGHT_HERE;
-
     int32_t displayId = entry->displayId;
     int32_t action = entry->action;
     int32_t maskedAction = action & AMOTION_EVENT_ACTION_MASK;
@@ -1161,11 +1144,21 @@
     InjectionPermission injectionPermission = INJECTION_PERMISSION_UNKNOWN;
     sp<InputWindowHandle> newHoverWindowHandle;
 
-    bool isSplit = mTouchState.split;
-    bool switchedDevice = mTouchState.deviceId >= 0 && mTouchState.displayId >= 0
-            && (mTouchState.deviceId != entry->deviceId
-                    || mTouchState.source != entry->source
-                    || mTouchState.displayId != displayId);
+    // Copy current touch state into mTempTouchState.
+    // This state is always reset at the end of this function, so if we don't find state
+    // for the specified display then our initial state will be empty.
+    const TouchState* oldState = NULL;
+    ssize_t oldStateIndex = mTouchStatesByDisplay.indexOfKey(displayId);
+    if (oldStateIndex >= 0) {
+        oldState = &mTouchStatesByDisplay.valueAt(oldStateIndex);
+        mTempTouchState.copyFrom(*oldState);
+    }
+
+    bool isSplit = mTempTouchState.split;
+    bool switchedDevice = mTempTouchState.deviceId >= 0 && mTempTouchState.displayId >= 0
+            && (mTempTouchState.deviceId != entry->deviceId
+                    || mTempTouchState.source != entry->source
+                    || mTempTouchState.displayId != displayId);
     bool isHoverAction = (maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE
             || maskedAction == AMOTION_EVENT_ACTION_HOVER_ENTER
             || maskedAction == AMOTION_EVENT_ACTION_HOVER_EXIT);
@@ -1175,11 +1168,10 @@
     bool wrongDevice = false;
     if (newGesture) {
         bool down = maskedAction == AMOTION_EVENT_ACTION_DOWN;
-        if (switchedDevice && mTouchState.down && !down) {
+        if (switchedDevice && mTempTouchState.down && !down) {
 #if DEBUG_FOCUS
             ALOGD("Dropping event because a pointer for a different device is already down.");
 #endif
-            mTempTouchState.copyFrom(mTouchState);
             injectionResult = INPUT_EVENT_INJECTION_FAILED;
             switchedDevice = false;
             wrongDevice = true;
@@ -1191,8 +1183,6 @@
         mTempTouchState.source = entry->source;
         mTempTouchState.displayId = displayId;
         isSplit = false;
-    } else {
-        mTempTouchState.copyFrom(mTouchState);
     }
 
     if (newGesture || (isSplit && maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN)) {
@@ -1229,10 +1219,7 @@
                     isTouchModal = (flags & (InputWindowInfo::FLAG_NOT_FOCUSABLE
                             | InputWindowInfo::FLAG_NOT_TOUCH_MODAL)) == 0;
                     if (isTouchModal || windowInfo->touchableRegionContainsPoint(x, y)) {
-                        if (! screenWasOff
-                                || (flags & InputWindowInfo::FLAG_TOUCHABLE_WHEN_WAKING)) {
-                            newTouchedWindowHandle = windowHandle;
-                        }
+                        newTouchedWindowHandle = windowHandle;
                         break; // found touched window, exit window loop
                     }
                 }
@@ -1515,32 +1502,31 @@
 
             if (isHoverAction) {
                 // Started hovering, therefore no longer down.
-                if (mTouchState.down) {
+                if (oldState && oldState->down) {
 #if DEBUG_FOCUS
                     ALOGD("Conflicting pointer actions: Hover received while pointer was down.");
 #endif
                     *outConflictingPointerActions = true;
                 }
-                mTouchState.reset();
+                mTempTouchState.reset();
                 if (maskedAction == AMOTION_EVENT_ACTION_HOVER_ENTER
                         || maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE) {
-                    mTouchState.deviceId = entry->deviceId;
-                    mTouchState.source = entry->source;
-                    mTouchState.displayId = displayId;
+                    mTempTouchState.deviceId = entry->deviceId;
+                    mTempTouchState.source = entry->source;
+                    mTempTouchState.displayId = displayId;
                 }
             } else if (maskedAction == AMOTION_EVENT_ACTION_UP
                     || maskedAction == AMOTION_EVENT_ACTION_CANCEL) {
                 // All pointers up or canceled.
-                mTouchState.reset();
+                mTempTouchState.reset();
             } else if (maskedAction == AMOTION_EVENT_ACTION_DOWN) {
                 // First pointer went down.
-                if (mTouchState.down) {
+                if (oldState && oldState->down) {
 #if DEBUG_FOCUS
                     ALOGD("Conflicting pointer actions: Down received while already down.");
 #endif
                     *outConflictingPointerActions = true;
                 }
-                mTouchState.copyFrom(mTempTouchState);
             } else if (maskedAction == AMOTION_EVENT_ACTION_POINTER_UP) {
                 // One pointer went up.
                 if (isSplit) {
@@ -1559,12 +1545,20 @@
                         i += 1;
                     }
                 }
-                mTouchState.copyFrom(mTempTouchState);
-            } else if (maskedAction == AMOTION_EVENT_ACTION_SCROLL) {
-                // Discard temporary touch state since it was only valid for this action.
-            } else {
-                // Save changes to touch state as-is for all other actions.
-                mTouchState.copyFrom(mTempTouchState);
+            }
+
+            // Save changes unless the action was scroll in which case the temporary touch
+            // state was only valid for this one action.
+            if (maskedAction != AMOTION_EVENT_ACTION_SCROLL) {
+                if (mTempTouchState.displayId >= 0) {
+                    if (oldStateIndex >= 0) {
+                        mTouchStatesByDisplay.editValueAt(oldStateIndex).copyFrom(mTempTouchState);
+                    } else {
+                        mTouchStatesByDisplay.add(displayId, mTempTouchState);
+                    }
+                } else if (oldStateIndex >= 0) {
+                    mTouchStatesByDisplay.removeItemsAt(oldStateIndex);
+                }
             }
 
             // Update hover state.
@@ -2316,7 +2310,7 @@
             originalMotionEntry->yPrecision,
             originalMotionEntry->downTime,
             originalMotionEntry->displayId,
-            splitPointerCount, splitPointerProperties, splitPointerCoords);
+            splitPointerCount, splitPointerProperties, splitPointerCoords, 0, 0);
 
     if (originalMotionEntry->injectionState) {
         splitMotionEntry->injectionState = originalMotionEntry->injectionState;
@@ -2388,10 +2382,6 @@
 
     mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags);
 
-    if (policyFlags & POLICY_FLAG_WOKE_HERE) {
-        flags |= AKEY_EVENT_FLAG_WOKE_HERE;
-    }
-
     bool needWake;
     { // acquire lock
         mLock.lock();
@@ -2488,7 +2478,7 @@
                 args->action, args->flags, args->metaState, args->buttonState,
                 args->edgeFlags, args->xPrecision, args->yPrecision, args->downTime,
                 args->displayId,
-                args->pointerCount, args->pointerProperties, args->pointerCoords);
+                args->pointerCount, args->pointerProperties, args->pointerCoords, 0, 0);
 
         needWake = enqueueInboundEventLocked(newEntry);
         mLock.unlock();
@@ -2536,7 +2526,7 @@
     }
 }
 
-int32_t InputDispatcher::injectInputEvent(const InputEvent* event,
+int32_t InputDispatcher::injectInputEvent(const InputEvent* event, int32_t displayId,
         int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis,
         uint32_t policyFlags) {
 #if DEBUG_INBOUND_EVENT_DETAILS
@@ -2571,10 +2561,6 @@
             mPolicy->interceptKeyBeforeQueueing(keyEvent, /*byref*/ policyFlags);
         }
 
-        if (policyFlags & POLICY_FLAG_WOKE_HERE) {
-            flags |= AKEY_EVENT_FLAG_WOKE_HERE;
-        }
-
         mLock.lock();
         firstInjectedEntry = new KeyEntry(keyEvent->getEventTime(),
                 keyEvent->getDeviceId(), keyEvent->getSource(),
@@ -2587,7 +2573,6 @@
 
     case AINPUT_EVENT_TYPE_MOTION: {
         const MotionEvent* motionEvent = static_cast<const MotionEvent*>(event);
-        int32_t displayId = ADISPLAY_ID_DEFAULT;
         int32_t action = motionEvent->getAction();
         size_t pointerCount = motionEvent->getPointerCount();
         const PointerProperties* pointerProperties = motionEvent->getPointerProperties();
@@ -2610,7 +2595,8 @@
                 motionEvent->getEdgeFlags(),
                 motionEvent->getXPrecision(), motionEvent->getYPrecision(),
                 motionEvent->getDownTime(), displayId,
-                uint32_t(pointerCount), pointerProperties, samplePointerCoords);
+                uint32_t(pointerCount), pointerProperties, samplePointerCoords,
+                motionEvent->getXOffset(), motionEvent->getYOffset());
         lastInjectedEntry = firstInjectedEntry;
         for (size_t i = motionEvent->getHistorySize(); i > 0; i--) {
             sampleEventTimes += 1;
@@ -2622,7 +2608,8 @@
                     motionEvent->getEdgeFlags(),
                     motionEvent->getXPrecision(), motionEvent->getYPrecision(),
                     motionEvent->getDownTime(), displayId,
-                    uint32_t(pointerCount), pointerProperties, samplePointerCoords);
+                    uint32_t(pointerCount), pointerProperties, samplePointerCoords,
+                    motionEvent->getXOffset(), motionEvent->getYOffset());
             lastInjectedEntry->next = nextInjectedEntry;
             lastInjectedEntry = nextInjectedEntry;
         }
@@ -2847,22 +2834,25 @@
             mFocusedWindowHandle = newFocusedWindowHandle;
         }
 
-        for (size_t i = 0; i < mTouchState.windows.size(); i++) {
-            TouchedWindow& touchedWindow = mTouchState.windows.editItemAt(i);
-            if (!hasWindowHandleLocked(touchedWindow.windowHandle)) {
+        for (size_t d = 0; d < mTouchStatesByDisplay.size(); d++) {
+            TouchState& state = mTouchStatesByDisplay.editValueAt(d);
+            for (size_t i = 0; i < state.windows.size(); i++) {
+                TouchedWindow& touchedWindow = state.windows.editItemAt(i);
+                if (!hasWindowHandleLocked(touchedWindow.windowHandle)) {
 #if DEBUG_FOCUS
-                ALOGD("Touched window was removed: %s",
-                        touchedWindow.windowHandle->getName().string());
+                    ALOGD("Touched window was removed: %s",
+                            touchedWindow.windowHandle->getName().string());
 #endif
-                sp<InputChannel> touchedInputChannel =
-                        touchedWindow.windowHandle->getInputChannel();
-                if (touchedInputChannel != NULL) {
-                    CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS,
-                            "touched window was removed");
-                    synthesizeCancelationEventsForInputChannelLocked(
-                            touchedInputChannel, options);
+                    sp<InputChannel> touchedInputChannel =
+                            touchedWindow.windowHandle->getInputChannel();
+                    if (touchedInputChannel != NULL) {
+                        CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS,
+                                "touched window was removed");
+                        synthesizeCancelationEventsForInputChannelLocked(
+                                touchedInputChannel, options);
+                    }
+                    state.windows.removeAt(i--);
                 }
-                mTouchState.windows.removeAt(i--);
             }
         }
 
@@ -3003,23 +2993,27 @@
         }
 
         bool found = false;
-        for (size_t i = 0; i < mTouchState.windows.size(); i++) {
-            const TouchedWindow& touchedWindow = mTouchState.windows[i];
-            if (touchedWindow.windowHandle == fromWindowHandle) {
-                int32_t oldTargetFlags = touchedWindow.targetFlags;
-                BitSet32 pointerIds = touchedWindow.pointerIds;
+        for (size_t d = 0; d < mTouchStatesByDisplay.size(); d++) {
+            TouchState& state = mTouchStatesByDisplay.editValueAt(d);
+            for (size_t i = 0; i < state.windows.size(); i++) {
+                const TouchedWindow& touchedWindow = state.windows[i];
+                if (touchedWindow.windowHandle == fromWindowHandle) {
+                    int32_t oldTargetFlags = touchedWindow.targetFlags;
+                    BitSet32 pointerIds = touchedWindow.pointerIds;
 
-                mTouchState.windows.removeAt(i);
+                    state.windows.removeAt(i);
 
-                int32_t newTargetFlags = oldTargetFlags
-                        & (InputTarget::FLAG_FOREGROUND
-                                | InputTarget::FLAG_SPLIT | InputTarget::FLAG_DISPATCH_AS_IS);
-                mTouchState.addOrUpdateWindow(toWindowHandle, newTargetFlags, pointerIds);
+                    int32_t newTargetFlags = oldTargetFlags
+                            & (InputTarget::FLAG_FOREGROUND
+                                    | InputTarget::FLAG_SPLIT | InputTarget::FLAG_DISPATCH_AS_IS);
+                    state.addOrUpdateWindow(toWindowHandle, newTargetFlags, pointerIds);
 
-                found = true;
-                break;
+                    found = true;
+                    goto Found;
+                }
             }
         }
+Found:
 
         if (! found) {
 #if DEBUG_FOCUS
@@ -3063,7 +3057,7 @@
     drainInboundQueueLocked();
     resetANRTimeoutsLocked();
 
-    mTouchState.reset();
+    mTouchStatesByDisplay.clear();
     mLastHoverWindowHandle.clear();
 }
 
@@ -3098,22 +3092,28 @@
     dump.appendFormat(INDENT "FocusedWindow: name='%s'\n",
             mFocusedWindowHandle != NULL ? mFocusedWindowHandle->getName().string() : "<null>");
 
-    dump.appendFormat(INDENT "TouchDown: %s\n", toString(mTouchState.down));
-    dump.appendFormat(INDENT "TouchSplit: %s\n", toString(mTouchState.split));
-    dump.appendFormat(INDENT "TouchDeviceId: %d\n", mTouchState.deviceId);
-    dump.appendFormat(INDENT "TouchSource: 0x%08x\n", mTouchState.source);
-    dump.appendFormat(INDENT "TouchDisplayId: %d\n", mTouchState.displayId);
-    if (!mTouchState.windows.isEmpty()) {
-        dump.append(INDENT "TouchedWindows:\n");
-        for (size_t i = 0; i < mTouchState.windows.size(); i++) {
-            const TouchedWindow& touchedWindow = mTouchState.windows[i];
-            dump.appendFormat(INDENT2 "%zu: name='%s', pointerIds=0x%0x, targetFlags=0x%x\n",
-                    i, touchedWindow.windowHandle->getName().string(),
-                    touchedWindow.pointerIds.value,
-                    touchedWindow.targetFlags);
+    if (!mTouchStatesByDisplay.isEmpty()) {
+        dump.appendFormat(INDENT "TouchStatesByDisplay:\n");
+        for (size_t i = 0; i < mTouchStatesByDisplay.size(); i++) {
+            const TouchState& state = mTouchStatesByDisplay.valueAt(i);
+            dump.appendFormat(INDENT2 "%zu: down=%s, split=%s, deviceId=%d, source=0x%08x\n",
+                    state.displayId, toString(state.down), toString(state.split),
+                    state.deviceId, state.source);
+            if (!state.windows.isEmpty()) {
+                dump.append(INDENT3 "Windows:\n");
+                for (size_t i = 0; i < state.windows.size(); i++) {
+                    const TouchedWindow& touchedWindow = state.windows[i];
+                    dump.appendFormat(INDENT4 "%zu: name='%s', pointerIds=0x%0x, targetFlags=0x%x\n",
+                            i, touchedWindow.windowHandle->getName().string(),
+                            touchedWindow.pointerIds.value,
+                            touchedWindow.targetFlags);
+                }
+            } else {
+                dump.append(INDENT3 "Windows: <none>\n");
+            }
         }
     } else {
-        dump.append(INDENT "TouchedWindows: <none>\n");
+        dump.append(INDENT "TouchStates: <no displays touched>\n");
     }
 
     if (!mWindowHandles.isEmpty()) {
@@ -3898,7 +3898,8 @@
         int32_t metaState, int32_t buttonState,
         int32_t edgeFlags, float xPrecision, float yPrecision,
         nsecs_t downTime, int32_t displayId, uint32_t pointerCount,
-        const PointerProperties* pointerProperties, const PointerCoords* pointerCoords) :
+        const PointerProperties* pointerProperties, const PointerCoords* pointerCoords,
+        float xOffset, float yOffset) :
         EventEntry(TYPE_MOTION, eventTime, policyFlags),
         eventTime(eventTime),
         deviceId(deviceId), source(source), action(action), flags(flags),
@@ -3908,6 +3909,9 @@
     for (uint32_t i = 0; i < pointerCount; i++) {
         this->pointerProperties[i].copyFrom(pointerProperties[i]);
         this->pointerCoords[i].copyFrom(pointerCoords[i]);
+        if (xOffset || yOffset) {
+            this->pointerCoords[i].applyOffset(xOffset, yOffset);
+        }
     }
 }
 
@@ -4066,18 +4070,39 @@
     case AMOTION_EVENT_ACTION_POINTER_UP:
     case AMOTION_EVENT_ACTION_POINTER_DOWN:
     case AMOTION_EVENT_ACTION_MOVE: {
+        if (entry->source & AINPUT_SOURCE_CLASS_NAVIGATION) {
+            // Trackballs can send MOVE events with a corresponding DOWN or UP. There's no need to
+            // generate cancellation events for these since they're based in relative rather than
+            // absolute units.
+            return true;
+        }
+
         ssize_t index = findMotionMemento(entry, false /*hovering*/);
+
+        if (entry->source & AINPUT_SOURCE_CLASS_JOYSTICK) {
+            // Joysticks can send MOVE events without a corresponding DOWN or UP. Since all
+            // joystick axes are normalized to [-1, 1] we can trust that 0 means it's neutral. Any
+            // other value and we need to track the motion so we can send cancellation events for
+            // anything generating fallback events (e.g. DPad keys for joystick movements).
+            if (index >= 0) {
+                if (entry->pointerCoords[0].isEmpty()) {
+                    mMotionMementos.removeAt(index);
+                } else {
+                    MotionMemento& memento = mMotionMementos.editItemAt(index);
+                    memento.setPointers(entry);
+                }
+            } else if (!entry->pointerCoords[0].isEmpty()) {
+                addMotionMemento(entry, flags, false /*hovering*/);
+            }
+
+            // Joysticks and trackballs can send MOVE events without corresponding DOWN or UP.
+            return true;
+        }
         if (index >= 0) {
             MotionMemento& memento = mMotionMementos.editItemAt(index);
             memento.setPointers(entry);
             return true;
         }
-        if (actionMasked == AMOTION_EVENT_ACTION_MOVE
-                && (entry->source & (AINPUT_SOURCE_CLASS_JOYSTICK
-                        | AINPUT_SOURCE_CLASS_NAVIGATION))) {
-            // Joysticks and trackballs can send MOVE events without corresponding DOWN or UP.
-            return true;
-        }
 #if DEBUG_OUTBOUND_EVENT_DETAILS
         ALOGD("Dropping inconsistent motion pointer up/down or move event: "
                 "deviceId=%d, source=%08x, actionMasked=%d",
@@ -4201,7 +4226,8 @@
                     memento.flags, 0, 0, 0,
                     memento.xPrecision, memento.yPrecision, memento.downTime,
                     memento.displayId,
-                    memento.pointerCount, memento.pointerProperties, memento.pointerCoords));
+                    memento.pointerCount, memento.pointerProperties, memento.pointerCoords,
+                    0, 0));
         }
     }
 }
diff --git a/services/input/InputDispatcher.h b/libs/input/InputDispatcher.h
similarity index 98%
rename from services/input/InputDispatcher.h
rename to libs/input/InputDispatcher.h
index 190e7b2..9439124 100644
--- a/services/input/InputDispatcher.h
+++ b/libs/input/InputDispatcher.h
@@ -211,9 +211,6 @@
     /* Gets the input dispatcher configuration. */
     virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) = 0;
 
-    /* Returns true if automatic key repeating is enabled. */
-    virtual bool isKeyRepeatEnabled() = 0;
-
     /* Filters an input event.
      * Return true to dispatch the event unmodified, false to consume the event.
      * A filter can also transform and inject events later by passing POLICY_FLAG_FILTERED
@@ -297,7 +294,7 @@
      *
      * This method may be called on any thread (usually by the input manager).
      */
-    virtual int32_t injectInputEvent(const InputEvent* event,
+    virtual int32_t injectInputEvent(const InputEvent* event, int32_t displayId,
             int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis,
             uint32_t policyFlags) = 0;
 
@@ -381,7 +378,7 @@
     virtual void notifySwitch(const NotifySwitchArgs* args);
     virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args);
 
-    virtual int32_t injectInputEvent(const InputEvent* event,
+    virtual int32_t injectInputEvent(const InputEvent* event, int32_t displayId,
             int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis,
             uint32_t policyFlags);
 
@@ -525,7 +522,8 @@
                 int32_t metaState, int32_t buttonState, int32_t edgeFlags,
                 float xPrecision, float yPrecision,
                 nsecs_t downTime, int32_t displayId, uint32_t pointerCount,
-                const PointerProperties* pointerProperties, const PointerCoords* pointerCoords);
+                const PointerProperties* pointerProperties, const PointerCoords* pointerCoords,
+                float xOffset, float yOffset);
         virtual void appendDescription(String8& msg) const;
 
     protected:
@@ -959,7 +957,7 @@
         bool isSlippery() const;
     };
 
-    TouchState mTouchState;
+    KeyedVector<int32_t, TouchState> mTouchStatesByDisplay;
     TouchState mTempTouchState;
 
     // Focused application.
diff --git a/services/input/InputListener.cpp b/libs/input/InputListener.cpp
similarity index 100%
rename from services/input/InputListener.cpp
rename to libs/input/InputListener.cpp
diff --git a/services/input/InputListener.h b/libs/input/InputListener.h
similarity index 100%
rename from services/input/InputListener.h
rename to libs/input/InputListener.h
diff --git a/services/input/InputManager.cpp b/libs/input/InputManager.cpp
similarity index 100%
rename from services/input/InputManager.cpp
rename to libs/input/InputManager.cpp
diff --git a/services/input/InputManager.h b/libs/input/InputManager.h
similarity index 100%
rename from services/input/InputManager.h
rename to libs/input/InputManager.h
diff --git a/services/input/InputReader.cpp b/libs/input/InputReader.cpp
similarity index 99%
rename from services/input/InputReader.cpp
rename to libs/input/InputReader.cpp
index d86fa4f..a4093e9 100644
--- a/services/input/InputReader.cpp
+++ b/libs/input/InputReader.cpp
@@ -911,7 +911,7 @@
         if (!changes || (changes & InputReaderConfiguration::CHANGE_KEYBOARD_LAYOUTS)) {
             if (!(mClasses & INPUT_DEVICE_CLASS_VIRTUAL)) {
                 sp<KeyCharacterMap> keyboardLayout =
-                        mContext->getPolicy()->getKeyboardLayoutOverlay(mIdentifier.descriptor);
+                        mContext->getPolicy()->getKeyboardLayoutOverlay(mIdentifier);
                 if (mContext->getEventHub()->setKeyboardLayoutOverlay(mId, keyboardLayout)) {
                     bumpGeneration();
                 }
@@ -2030,6 +2030,10 @@
     if (mParameters.orientationAware) {
         mParameters.hasAssociatedDisplay = true;
     }
+
+    mParameters.handlesKeyRepeat = false;
+    getDevice()->getConfiguration().tryGetProperty(String8("keyboard.handlesKeyRepeat"),
+            mParameters.handlesKeyRepeat);
 }
 
 void KeyboardInputMapper::dumpParameters(String8& dump) {
@@ -2038,6 +2042,8 @@
             toString(mParameters.hasAssociatedDisplay));
     dump.appendFormat(INDENT4 "OrientationAware: %s\n",
             toString(mParameters.orientationAware));
+    dump.appendFormat(INDENT4 "HandlesKeyRepeat: %s\n",
+            toString(mParameters.handlesKeyRepeat));
 }
 
 void KeyboardInputMapper::reset(nsecs_t when) {
@@ -2155,6 +2161,10 @@
         policyFlags |= POLICY_FLAG_WAKE_DROPPED;
     }
 
+    if (mParameters.handlesKeyRepeat) {
+        policyFlags |= POLICY_FLAG_DISABLE_KEY_REPEAT;
+    }
+
     if (metaStateChanged) {
         getContext()->updateGlobalMetaState();
     }
@@ -2197,9 +2207,9 @@
 }
 
 void KeyboardInputMapper::resetLedState() {
-    initializeLedState(mCapsLockLedState, LED_CAPSL);
-    initializeLedState(mNumLockLedState, LED_NUML);
-    initializeLedState(mScrollLockLedState, LED_SCROLLL);
+    initializeLedState(mCapsLockLedState, ALED_CAPS_LOCK);
+    initializeLedState(mNumLockLedState, ALED_NUM_LOCK);
+    initializeLedState(mScrollLockLedState, ALED_SCROLL_LOCK);
 
     updateLedState(true);
 }
@@ -2210,11 +2220,11 @@
 }
 
 void KeyboardInputMapper::updateLedState(bool reset) {
-    updateLedStateForModifier(mCapsLockLedState, LED_CAPSL,
+    updateLedStateForModifier(mCapsLockLedState, ALED_CAPS_LOCK,
             AMETA_CAPS_LOCK_ON, reset);
-    updateLedStateForModifier(mNumLockLedState, LED_NUML,
+    updateLedStateForModifier(mNumLockLedState, ALED_NUM_LOCK,
             AMETA_NUM_LOCK_ON, reset);
-    updateLedStateForModifier(mScrollLockLedState, LED_SCROLLL,
+    updateLedStateForModifier(mScrollLockLedState, ALED_SCROLL_LOCK,
             AMETA_SCROLL_LOCK_ON, reset);
 }
 
@@ -2831,6 +2841,13 @@
                 mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN
                         && getDevice()->isExternal();
     }
+
+    // Initial downs on external touch devices should wake the device.
+    // Normally we don't do this for internal touch screens to prevent them from waking
+    // up in your pocket but you can enable it using the input device configuration.
+    mParameters.wake = getDevice()->isExternal();
+    getDevice()->getConfiguration().tryGetProperty(String8("touch.wake"),
+            mParameters.wake);
 }
 
 void TouchInputMapper::dumpParameters(String8& dump) {
@@ -3733,11 +3750,7 @@
                 getContext()->fadePointer();
             }
 
-            // Initial downs on external touch devices should wake the device.
-            // We don't do this for internal touch screens to prevent them from waking
-            // up in your pocket.
-            // TODO: Use the input device configuration to control this behavior more finely.
-            if (getDevice()->isExternal()) {
+            if (mParameters.wake) {
                 policyFlags |= POLICY_FLAG_WAKE_DROPPED;
             }
         }
diff --git a/services/input/InputReader.h b/libs/input/InputReader.h
similarity index 99%
rename from services/input/InputReader.h
rename to libs/input/InputReader.h
index a8bb636..c90d483 100644
--- a/services/input/InputReader.h
+++ b/libs/input/InputReader.h
@@ -281,7 +281,8 @@
     virtual void notifyInputDevicesChanged(const Vector<InputDeviceInfo>& inputDevices) = 0;
 
     /* Gets the keyboard layout for a particular input device. */
-    virtual sp<KeyCharacterMap> getKeyboardLayoutOverlay(const String8& inputDeviceDescriptor) = 0;
+    virtual sp<KeyCharacterMap> getKeyboardLayoutOverlay(
+            const InputDeviceIdentifier& identifier) = 0;
 
     /* Gets a user-supplied alias for a particular input device, or an empty string if none. */
     virtual String8 getDeviceAlias(const InputDeviceIdentifier& identifier) = 0;
@@ -1053,6 +1054,7 @@
     struct Parameters {
         bool hasAssociatedDisplay;
         bool orientationAware;
+        bool handlesKeyRepeat;
     } mParameters;
 
     void configureParameters();
@@ -1214,6 +1216,8 @@
             GESTURE_MODE_SPOTS,
         };
         GestureMode gestureMode;
+
+        bool wake;
     } mParameters;
 
     // Immutable calibration parameters in parsed form.
diff --git a/services/input/InputWindow.cpp b/libs/input/InputWindow.cpp
similarity index 100%
rename from services/input/InputWindow.cpp
rename to libs/input/InputWindow.cpp
diff --git a/services/input/InputWindow.h b/libs/input/InputWindow.h
similarity index 100%
rename from services/input/InputWindow.h
rename to libs/input/InputWindow.h
diff --git a/services/input/PointerController.cpp b/libs/input/PointerController.cpp
similarity index 100%
rename from services/input/PointerController.cpp
rename to libs/input/PointerController.cpp
diff --git a/services/input/PointerController.h b/libs/input/PointerController.h
similarity index 100%
rename from services/input/PointerController.h
rename to libs/input/PointerController.h
diff --git a/services/input/SpriteController.cpp b/libs/input/SpriteController.cpp
similarity index 100%
rename from services/input/SpriteController.cpp
rename to libs/input/SpriteController.cpp
diff --git a/services/input/SpriteController.h b/libs/input/SpriteController.h
similarity index 100%
rename from services/input/SpriteController.h
rename to libs/input/SpriteController.h
diff --git a/services/input/tests/Android.mk b/libs/input/tests/Android.mk
similarity index 100%
rename from services/input/tests/Android.mk
rename to libs/input/tests/Android.mk
diff --git a/services/input/tests/InputDispatcher_test.cpp b/libs/input/tests/InputDispatcher_test.cpp
similarity index 94%
rename from services/input/tests/InputDispatcher_test.cpp
rename to libs/input/tests/InputDispatcher_test.cpp
index 26b4fab..7aac6ed 100644
--- a/services/input/tests/InputDispatcher_test.cpp
+++ b/libs/input/tests/InputDispatcher_test.cpp
@@ -27,6 +27,9 @@
 // An arbitrary device id.
 static const int32_t DEVICE_ID = 1;
 
+// An arbitrary display id.
+static const int32_t DISPLAY_ID = 0;
+
 // An arbitrary injector pid / uid pair that has permission to inject events.
 static const int32_t INJECTOR_PID = 999;
 static const int32_t INJECTOR_UID = 1001;
@@ -62,10 +65,6 @@
         *outConfig = mConfig;
     }
 
-    virtual bool isKeyRepeatEnabled() {
-        return true;
-    }
-
     virtual bool filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags) {
         return true;
     }
@@ -126,7 +125,8 @@
     event.initialize(DEVICE_ID, AINPUT_SOURCE_KEYBOARD,
             /*action*/ -1, 0,
             AKEYCODE_A, KEY_A, AMETA_NONE, 0, ARBITRARY_TIME, ARBITRARY_TIME);
-    ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event,
+    ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
+            &event, DISPLAY_ID,
             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
             << "Should reject key events with undefined action.";
 
@@ -134,7 +134,8 @@
     event.initialize(DEVICE_ID, AINPUT_SOURCE_KEYBOARD,
             AKEY_EVENT_ACTION_MULTIPLE, 0,
             AKEYCODE_A, KEY_A, AMETA_NONE, 0, ARBITRARY_TIME, ARBITRARY_TIME);
-    ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event,
+    ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
+            &event, DISPLAY_ID,
             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
             << "Should reject key events with ACTION_MULTIPLE.";
 }
@@ -154,7 +155,8 @@
             /*action*/ -1, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
             ARBITRARY_TIME, ARBITRARY_TIME,
             /*pointerCount*/ 1, pointerProperties, pointerCoords);
-    ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event,
+    ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
+            &event, DISPLAY_ID,
             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
             << "Should reject motion events with undefined action.";
 
@@ -164,7 +166,8 @@
             0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
             ARBITRARY_TIME, ARBITRARY_TIME,
             /*pointerCount*/ 1, pointerProperties, pointerCoords);
-    ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event,
+    ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
+            &event, DISPLAY_ID,
             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
             << "Should reject motion events with pointer down index too large.";
 
@@ -173,7 +176,8 @@
             0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
             ARBITRARY_TIME, ARBITRARY_TIME,
             /*pointerCount*/ 1, pointerProperties, pointerCoords);
-    ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event,
+    ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
+            &event, DISPLAY_ID,
             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
             << "Should reject motion events with pointer down index too small.";
 
@@ -183,7 +187,8 @@
             0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
             ARBITRARY_TIME, ARBITRARY_TIME,
             /*pointerCount*/ 1, pointerProperties, pointerCoords);
-    ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event,
+    ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
+            &event, DISPLAY_ID,
             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
             << "Should reject motion events with pointer up index too large.";
 
@@ -192,7 +197,8 @@
             0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
             ARBITRARY_TIME, ARBITRARY_TIME,
             /*pointerCount*/ 1, pointerProperties, pointerCoords);
-    ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event,
+    ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
+            &event, DISPLAY_ID,
             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
             << "Should reject motion events with pointer up index too small.";
 
@@ -201,7 +207,8 @@
             AMOTION_EVENT_ACTION_DOWN, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
             ARBITRARY_TIME, ARBITRARY_TIME,
             /*pointerCount*/ 0, pointerProperties, pointerCoords);
-    ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event,
+    ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
+            &event, DISPLAY_ID,
             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
             << "Should reject motion events with 0 pointers.";
 
@@ -209,7 +216,8 @@
             AMOTION_EVENT_ACTION_DOWN, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
             ARBITRARY_TIME, ARBITRARY_TIME,
             /*pointerCount*/ MAX_POINTERS + 1, pointerProperties, pointerCoords);
-    ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event,
+    ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
+            &event, DISPLAY_ID,
             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
             << "Should reject motion events with more than MAX_POINTERS pointers.";
 
@@ -219,7 +227,8 @@
             AMOTION_EVENT_ACTION_DOWN, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
             ARBITRARY_TIME, ARBITRARY_TIME,
             /*pointerCount*/ 1, pointerProperties, pointerCoords);
-    ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event,
+    ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
+            &event, DISPLAY_ID,
             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
             << "Should reject motion events with pointer ids less than 0.";
 
@@ -228,7 +237,8 @@
             AMOTION_EVENT_ACTION_DOWN, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
             ARBITRARY_TIME, ARBITRARY_TIME,
             /*pointerCount*/ 1, pointerProperties, pointerCoords);
-    ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event,
+    ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
+            &event, DISPLAY_ID,
             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
             << "Should reject motion events with pointer ids greater than MAX_POINTER_ID.";
 
@@ -239,7 +249,8 @@
             AMOTION_EVENT_ACTION_DOWN, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
             ARBITRARY_TIME, ARBITRARY_TIME,
             /*pointerCount*/ 2, pointerProperties, pointerCoords);
-    ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(&event,
+    ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
+            &event, DISPLAY_ID,
             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
             << "Should reject motion events with duplicate pointer ids.";
 }
diff --git a/services/input/tests/InputReader_test.cpp b/libs/input/tests/InputReader_test.cpp
similarity index 99%
rename from services/input/tests/InputReader_test.cpp
rename to libs/input/tests/InputReader_test.cpp
index f068732..aaa973d 100644
--- a/services/input/tests/InputReader_test.cpp
+++ b/libs/input/tests/InputReader_test.cpp
@@ -186,7 +186,7 @@
         mInputDevices = inputDevices;
     }
 
-    virtual sp<KeyCharacterMap> getKeyboardLayoutOverlay(const String8& inputDeviceDescriptor) {
+    virtual sp<KeyCharacterMap> getKeyboardLayoutOverlay(const InputDeviceIdentifier& identifier) {
         return NULL;
     }
 
diff --git a/media/java/android/media/MediaDrm.java b/media/java/android/media/MediaDrm.java
index f5a703b..532e39a 100644
--- a/media/java/android/media/MediaDrm.java
+++ b/media/java/android/media/MediaDrm.java
@@ -21,6 +21,8 @@
 import java.util.UUID;
 import java.util.HashMap;
 import java.util.List;
+import android.os.Binder;
+import android.os.Debug;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
@@ -97,12 +99,28 @@
 
     private final static String TAG = "MediaDrm";
 
+    private static final String PERMISSION = android.Manifest.permission.ACCESS_DRM_CERTIFICATES;
+
     private EventHandler mEventHandler;
     private OnEventListener mOnEventListener;
 
     private long mNativeContext;
 
     /**
+     * Specify no certificate type
+     *
+     * @hide - not part of the public API at this time
+     */
+    public static final int CERTIFICATE_TYPE_NONE = 0;
+
+    /**
+     * Specify X.509 certificate type
+     *
+     * @hide - not part of the public API at this time
+     */
+    public static final int CERTIFICATE_TYPE_X509 = 1;
+
+    /**
      * Query if the given scheme identified by its UUID is supported on
      * this device.
      * @param uuid The UUID of the crypto scheme.
@@ -137,7 +155,7 @@
     }
 
     private static final native boolean isCryptoSchemeSupportedNative(byte[] uuid,
-                                                                      String mimeType);
+            String mimeType);
 
     /**
      * Instantiate a MediaDrm object
@@ -161,7 +179,7 @@
          * It's easier to create it here than in C++.
          */
         native_setup(new WeakReference<MediaDrm>(this),
-                     getByteArrayFromUUID(uuid));
+                getByteArrayFromUUID(uuid));
     }
 
     /**
@@ -270,7 +288,7 @@
      * the cookie passed to native_setup().)
      */
     private static void postEventFromNative(Object mediadrm_ref,
-                                            int eventType, int extra, Object obj)
+            int eventType, int extra, Object obj)
     {
         MediaDrm md = (MediaDrm)((WeakReference)mediadrm_ref).get();
         if (md == null) {
@@ -318,6 +336,9 @@
      * Contains the opaque data an app uses to request keys from a license server
      */
     public final static class KeyRequest {
+        private byte[] mData;
+        private String mDefaultUrl;
+
         KeyRequest() {}
 
         /**
@@ -331,9 +352,6 @@
          * server URL from other sources.
          */
         public String getDefaultUrl() { return mDefaultUrl; }
-
-        private byte[] mData;
-        private String mDefaultUrl;
     };
 
     /**
@@ -370,9 +388,8 @@
      * problem with the certifcate
      */
     public native KeyRequest getKeyRequest(byte[] scope, byte[] init,
-                                           String mimeType, int keyType,
-                                           HashMap<String, String> optionalParameters)
-        throws NotProvisionedException;
+            String mimeType, int keyType, HashMap<String, String> optionalParameters)
+            throws NotProvisionedException;
 
 
     /**
@@ -396,7 +413,7 @@
      * @throws ResourceBusyException if required resources are in use
      */
     public native byte[] provideKeyResponse(byte[] scope, byte[] response)
-        throws NotProvisionedException, DeniedByServerException;
+            throws NotProvisionedException, DeniedByServerException;
 
 
     /**
@@ -458,7 +475,12 @@
      * is returned in ProvisionRequest.data. The recommended URL to deliver the provision
      * request to is returned in ProvisionRequest.defaultUrl.
      */
-    public native ProvisionRequest getProvisionRequest();
+    public ProvisionRequest getProvisionRequest() {
+        return getProvisionRequestNative(CERTIFICATE_TYPE_NONE, "");
+    }
+
+    private native ProvisionRequest getProvisionRequestNative(int certType,
+            String certAuthority);
 
     /**
      * After a provision response is received by the app, it is provided to the DRM
@@ -470,8 +492,13 @@
      * @throws DeniedByServerException if the response indicates that the
      * server rejected the request
      */
-    public native void provideProvisionResponse(byte[] response)
-        throws DeniedByServerException;
+    public void provideProvisionResponse(byte[] response)
+            throws DeniedByServerException {
+        provideProvisionResponseNative(response);
+    }
+
+    private native Certificate provideProvisionResponseNative(byte[] response)
+            throws DeniedByServerException;
 
     /**
      * A means of enforcing limits on the number of concurrent streams per subscriber
@@ -558,23 +585,22 @@
 
 
     private static final native void setCipherAlgorithmNative(MediaDrm drm, byte[] sessionId,
-                                                              String algorithm);
+            String algorithm);
 
     private static final native void setMacAlgorithmNative(MediaDrm drm, byte[] sessionId,
-                                                           String algorithm);
+            String algorithm);
 
     private static final native byte[] encryptNative(MediaDrm drm, byte[] sessionId,
-                                                     byte[] keyId, byte[] input, byte[] iv);
+            byte[] keyId, byte[] input, byte[] iv);
 
     private static final native byte[] decryptNative(MediaDrm drm, byte[] sessionId,
-                                                     byte[] keyId, byte[] input, byte[] iv);
+            byte[] keyId, byte[] input, byte[] iv);
 
     private static final native byte[] signNative(MediaDrm drm, byte[] sessionId,
-                                                  byte[] keyId, byte[] message);
+            byte[] keyId, byte[] message);
 
     private static final native boolean verifyNative(MediaDrm drm, byte[] sessionId,
-                                                     byte[] keyId, byte[] message,
-                                                     byte[] signature);
+            byte[] keyId, byte[] message, byte[] signature);
 
     /**
      * In addition to supporting decryption of DASH Common Encrypted Media, the
@@ -604,7 +630,7 @@
         private byte[] mSessionId;
 
         CryptoSession(MediaDrm drm, byte[] sessionId,
-                      String cipherAlgorithm, String macAlgorithm)
+                String cipherAlgorithm, String macAlgorithm)
         {
             mSessionId = sessionId;
             mDrm = drm;
@@ -679,12 +705,124 @@
      * "algorithms".
      */
     public CryptoSession getCryptoSession(byte[] sessionId,
-                                          String cipherAlgorithm,
-                                          String macAlgorithm)
+            String cipherAlgorithm, String macAlgorithm)
     {
         return new CryptoSession(this, sessionId, cipherAlgorithm, macAlgorithm);
     }
 
+    /**
+     * Contains the opaque data an app uses to request a certificate from a provisioning
+     * server
+     *
+     * @hide - not part of the public API at this time
+     */
+    public final static class CertificateRequest {
+        private byte[] mData;
+        private String mDefaultUrl;
+
+        CertificateRequest(byte[] data, String defaultUrl) {
+            mData = data;
+            mDefaultUrl = defaultUrl;
+        }
+
+        /**
+         * Get the opaque message data
+         */
+        public byte[] getData() { return mData; }
+
+        /**
+         * Get the default URL to use when sending the certificate request
+         * message to a server, if known. The app may prefer to use a different
+         * certificate server URL obtained from other sources.
+         */
+        public String getDefaultUrl() { return mDefaultUrl; }
+    }
+
+    /**
+     * Generate a certificate request, specifying the certificate type
+     * and authority. The response received should be passed to
+     * provideCertificateResponse.
+     *
+     * @param certType Specifies the certificate type.
+     *
+     * @param certAuthority is passed to the certificate server to specify
+     * the chain of authority.
+     *
+     * @hide - not part of the public API at this time
+     */
+    public CertificateRequest getCertificateRequest(int certType,
+            String certAuthority)
+    {
+        ProvisionRequest provisionRequest = getProvisionRequestNative(certType, certAuthority);
+        return new CertificateRequest(provisionRequest.getData(),
+                provisionRequest.getDefaultUrl());
+    }
+
+    /**
+     * Contains the wrapped private key and public certificate data associated
+     * with a certificate.
+     *
+     * @hide - not part of the public API at this time
+     */
+    public final static class Certificate {
+        Certificate() {}
+
+        /**
+         * Get the wrapped private key data
+         */
+        public byte[] getWrappedPrivateKey() { return mWrappedKey; }
+
+        /**
+         * Get the PEM-encoded certificate chain
+         */
+        public byte[] getContent() { return mCertificateData; }
+
+        private byte[] mWrappedKey;
+        private byte[] mCertificateData;
+    }
+
+
+    /**
+     * Process a response from the certificate server.  The response
+     * is obtained from an HTTP Post to the url provided by getCertificateRequest.
+     * <p>
+     * The public X509 certificate chain and wrapped private key are returned
+     * in the returned Certificate objec.  The certificate chain is in PEM format.
+     * The wrapped private key should be stored in application private
+     * storage, and used when invoking the signRSA method.
+     *
+     * @param response the opaque certificate response byte array to provide to the
+     * DRM engine plugin.
+     *
+     * @throws DeniedByServerException if the response indicates that the
+     * server rejected the request
+     *
+     * @hide - not part of the public API at this time
+     */
+    public Certificate provideCertificateResponse(byte[] response)
+            throws DeniedByServerException {
+        return provideProvisionResponseNative(response);
+    }
+
+    private static final native byte[] signRSANative(MediaDrm drm, byte[] sessionId,
+            String algorithm, byte[] wrappedKey, byte[] message);
+
+    /**
+     * Sign data using an RSA key
+     *
+     * @param sessionId a sessionId obtained from openSession on the MediaDrm object
+     * @param algorithm the signing algorithm to use, e.g. "PKCS1-BlockType1"
+     * @param wrappedKey - the wrapped (encrypted) RSA private key obtained
+     * from provideCertificateResponse
+     * @param message the data for which a signature is to be computed
+     *
+     * @hide - not part of the public API at this time
+     */
+    public byte[] signRSA(byte[] sessionId, String algorithm,
+            byte[] wrappedKey, byte[] message) {
+        return signRSANative(this, sessionId, algorithm, wrappedKey, message);
+    }
+
     @Override
     protected void finalize() {
         native_finalize();
diff --git a/media/java/android/media/Ringtone.java b/media/java/android/media/Ringtone.java
index 1283e9b..2616b6c 100644
--- a/media/java/android/media/Ringtone.java
+++ b/media/java/android/media/Ringtone.java
@@ -217,7 +217,7 @@
             if (mAudioManager.getStreamVolume(mStreamType) != 0) {
                 mLocalPlayer.start();
             }
-        } else if (mAllowRemote) {
+        } else if (mAllowRemote && (mRemotePlayer != null)) {
             final Uri canonicalUri = mUri.getCanonicalUri();
             try {
                 mRemotePlayer.play(mRemoteToken, canonicalUri, mStreamType);
@@ -239,7 +239,7 @@
     public void stop() {
         if (mLocalPlayer != null) {
             destroyLocalPlayer();
-        } else if (mAllowRemote) {
+        } else if (mAllowRemote && (mRemotePlayer != null)) {
             try {
                 mRemotePlayer.stop(mRemoteToken);
             } catch (RemoteException e) {
@@ -264,7 +264,7 @@
     public boolean isPlaying() {
         if (mLocalPlayer != null) {
             return mLocalPlayer.isPlaying();
-        } else if (mAllowRemote) {
+        } else if (mAllowRemote && (mRemotePlayer != null)) {
             try {
                 return mRemotePlayer.isPlaying(mRemoteToken);
             } catch (RemoteException e) {
diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp
index 052d97d..4fbd2a4 100644
--- a/media/jni/android_media_MediaDrm.cpp
+++ b/media/jni/android_media_MediaDrm.cpp
@@ -100,6 +100,16 @@
     jint kKeyTypeRelease;
 } gKeyTypes;
 
+struct CertificateTypes {
+    jint kCertificateTypeNone;
+    jint kCertificateTypeX509;
+} gCertificateTypes;
+
+struct CertificateFields {
+    jfieldID wrappedPrivateKey;
+    jfieldID certificateData;
+};
+
 struct fields_t {
     jfieldID context;
     jmethodID post_event;
@@ -110,6 +120,11 @@
     SetFields set;
     IteratorFields iterator;
     EntryFields entry;
+    CertificateFields certificate;
+    jclass certificateClassId;
+    jclass hashmapClassId;
+    jclass arraylistClassId;
+    jclass stringClassId;
 };
 
 static fields_t gFields;
@@ -282,8 +297,6 @@
 }
 
 JDrm::~JDrm() {
-    mDrm.clear();
-
     JNIEnv *env = AndroidRuntime::getJNIEnv();
 
     env->DeleteWeakGlobalRef(mObject);
@@ -348,6 +361,13 @@
     }
 }
 
+void JDrm::disconnect() {
+    if (mDrm != NULL) {
+        mDrm->destroyPlugin();
+        mDrm.clear();
+    }
+}
+
 
 // static
 bool JDrm::IsCryptoSchemeSupported(const uint8_t uuid[16], const String8 &mimeType) {
@@ -406,8 +426,7 @@
 */
 
 static KeyedVector<String8, String8> HashMapToKeyedVector(JNIEnv *env, jobject &hashMap) {
-    jclass clazz;
-    FIND_CLASS(clazz, "java/lang/String");
+    jclass clazz = gFields.stringClassId;
     KeyedVector<String8, String8> keyedVector;
 
     jobject entrySet = env->CallObjectMethod(hashMap, gFields.hashmap.entrySet);
@@ -450,8 +469,7 @@
 }
 
 static jobject KeyedVectorToHashMap (JNIEnv *env, KeyedVector<String8, String8> const &map) {
-    jclass clazz;
-    FIND_CLASS(clazz, "java/util/HashMap");
+    jclass clazz = gFields.hashmapClassId;
     jobject hashMap = env->NewObject(clazz, gFields.hashmap.init);
     for (size_t i = 0; i < map.size(); ++i) {
         jstring jkey = env->NewStringUTF(map.keyAt(i).string());
@@ -465,8 +483,7 @@
 
 static jobject ListOfVectorsToArrayListOfByteArray(JNIEnv *env,
                                                    List<Vector<uint8_t> > list) {
-    jclass clazz;
-    FIND_CLASS(clazz, "java/util/ArrayList");
+    jclass clazz = gFields.arraylistClassId;
     jobject arrayList = env->NewObject(clazz, gFields.arraylist.init);
     List<Vector<uint8_t> >::iterator iter = list.begin();
     while (iter != list.end()) {
@@ -515,6 +532,7 @@
     sp<JDrm> drm = setDrm(env, thiz, NULL);
     if (drm != NULL) {
         drm->setListener(NULL);
+        drm->disconnect();
     }
 }
 
@@ -542,6 +560,11 @@
     GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_RELEASE", "I");
     gKeyTypes.kKeyTypeRelease = env->GetStaticIntField(clazz, field);
 
+    GET_STATIC_FIELD_ID(field, clazz, "CERTIFICATE_TYPE_NONE", "I");
+    gCertificateTypes.kCertificateTypeNone = env->GetStaticIntField(clazz, field);
+    GET_STATIC_FIELD_ID(field, clazz, "CERTIFICATE_TYPE_X509", "I");
+    gCertificateTypes.kCertificateTypeX509 = env->GetStaticIntField(clazz, field);
+
     FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
     GET_FIELD_ID(gFields.keyRequest.data, clazz, "mData", "[B");
     GET_FIELD_ID(gFields.keyRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
@@ -550,6 +573,11 @@
     GET_FIELD_ID(gFields.provisionRequest.data, clazz, "mData", "[B");
     GET_FIELD_ID(gFields.provisionRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
 
+    FIND_CLASS(clazz, "android/media/MediaDrm$Certificate");
+    GET_FIELD_ID(gFields.certificate.wrappedPrivateKey, clazz, "mWrappedKey", "[B");
+    GET_FIELD_ID(gFields.certificate.certificateData, clazz, "mCertificateData", "[B");
+    gFields.certificateClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
+
     FIND_CLASS(clazz, "java/util/ArrayList");
     GET_METHOD_ID(gFields.arraylist.init, clazz, "<init>", "()V");
     GET_METHOD_ID(gFields.arraylist.add, clazz, "add", "(Ljava/lang/Object;)Z");
@@ -571,6 +599,15 @@
     FIND_CLASS(clazz, "java/util/Map$Entry");
     GET_METHOD_ID(gFields.entry.getKey, clazz, "getKey", "()Ljava/lang/Object;");
     GET_METHOD_ID(gFields.entry.getValue, clazz, "getValue", "()Ljava/lang/Object;");
+
+    FIND_CLASS(clazz, "java/util/HashMap");
+    gFields.hashmapClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
+
+    FIND_CLASS(clazz, "java/lang/String");
+    gFields.stringClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
+
+    FIND_CLASS(clazz, "java/util/ArrayList");
+    gFields.arraylistClassId = static_cast<jclass>(env->NewGlobalRef(clazz));
 }
 
 static void android_media_MediaDrm_native_setup(
@@ -826,8 +863,8 @@
     return KeyedVectorToHashMap(env, infoMap);
 }
 
-static jobject android_media_MediaDrm_getProvisionRequest(
-    JNIEnv *env, jobject thiz) {
+static jobject android_media_MediaDrm_getProvisionRequestNative(
+    JNIEnv *env, jobject thiz, jint jcertType, jstring jcertAuthority) {
     sp<IDrm> drm = GetDrm(env, thiz);
 
     if (drm == NULL) {
@@ -839,7 +876,17 @@
     Vector<uint8_t> request;
     String8 defaultUrl;
 
-    status_t err = drm->getProvisionRequest(request, defaultUrl);
+    String8 certType;
+    if (jcertType == gCertificateTypes.kCertificateTypeX509) {
+        certType = "X.509";
+    } else if (jcertType == gCertificateTypes.kCertificateTypeNone) {
+        certType = "none";
+    } else {
+        certType = "invalid";
+    }
+
+    String8 certAuthority = JStringToString8(env, jcertAuthority);
+    status_t err = drm->getProvisionRequest(certType, certAuthority, request, defaultUrl);
 
     if (throwExceptionAsNecessary(env, err, "Failed to get provision request")) {
         return NULL;
@@ -863,27 +910,43 @@
     return provisionObj;
 }
 
-static void android_media_MediaDrm_provideProvisionResponse(
+static jobject android_media_MediaDrm_provideProvisionResponseNative(
     JNIEnv *env, jobject thiz, jbyteArray jresponse) {
     sp<IDrm> drm = GetDrm(env, thiz);
 
     if (drm == NULL) {
         jniThrowException(env, "java/lang/IllegalStateException",
                           "MediaDrm obj is null");
-        return;
+        return NULL;
     }
 
     if (jresponse == NULL) {
         jniThrowException(env, "java/lang/IllegalArgumentException",
                           "provision response is null");
-        return;
+        return NULL;
     }
 
     Vector<uint8_t> response(JByteArrayToVector(env, jresponse));
+    Vector<uint8_t> certificate, wrappedKey;
 
-    status_t err = drm->provideProvisionResponse(response);
+    status_t err = drm->provideProvisionResponse(response, certificate, wrappedKey);
+
+    // Fill out return obj
+    jclass clazz = gFields.certificateClassId;
+
+    jobject certificateObj = NULL;
+
+    if (clazz && certificate.size() && wrappedKey.size()) {
+        certificateObj = env->AllocObject(clazz);
+        jbyteArray jcertificate = VectorToJByteArray(env, certificate);
+        env->SetObjectField(certificateObj, gFields.certificate.certificateData, jcertificate);
+
+        jbyteArray jwrappedKey = VectorToJByteArray(env, wrappedKey);
+        env->SetObjectField(certificateObj, gFields.certificate.wrappedPrivateKey, jwrappedKey);
+    }
 
     throwExceptionAsNecessary(env, err, "Failed to handle provision response");
+    return certificateObj;
 }
 
 static jobject android_media_MediaDrm_getSecureStops(
@@ -1209,6 +1272,38 @@
 }
 
 
+static jbyteArray android_media_MediaDrm_signRSANative(
+    JNIEnv *env, jobject thiz, jobject jdrm, jbyteArray jsessionId,
+    jstring jalgorithm, jbyteArray jwrappedKey, jbyteArray jmessage) {
+
+    sp<IDrm> drm = GetDrm(env, jdrm);
+
+    if (!CheckSession(env, drm, jsessionId)) {
+        return NULL;
+    }
+
+    if (jalgorithm == NULL || jwrappedKey == NULL || jmessage == NULL) {
+        jniThrowException(env, "java/lang/IllegalArgumentException",
+                          "required argument is null");
+        return NULL;
+    }
+
+    Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
+    String8 algorithm = JStringToString8(env, jalgorithm);
+    Vector<uint8_t> wrappedKey(JByteArrayToVector(env, jwrappedKey));
+    Vector<uint8_t> message(JByteArrayToVector(env, jmessage));
+    Vector<uint8_t> signature;
+
+    status_t err = drm->signRSA(sessionId, algorithm, message, wrappedKey, signature);
+
+    if (throwExceptionAsNecessary(env, err, "Failed to sign")) {
+        return NULL;
+    }
+
+    return VectorToJByteArray(env, signature);
+}
+
+
 static JNINativeMethod gMethods[] = {
     { "release", "()V", (void *)android_media_MediaDrm_release },
     { "native_init", "()V", (void *)android_media_MediaDrm_native_init },
@@ -1244,11 +1339,11 @@
     { "queryKeyStatus", "([B)Ljava/util/HashMap;",
       (void *)android_media_MediaDrm_queryKeyStatus },
 
-    { "getProvisionRequest", "()Landroid/media/MediaDrm$ProvisionRequest;",
-      (void *)android_media_MediaDrm_getProvisionRequest },
+    { "getProvisionRequestNative", "(ILjava/lang/String;)Landroid/media/MediaDrm$ProvisionRequest;",
+      (void *)android_media_MediaDrm_getProvisionRequestNative },
 
-    { "provideProvisionResponse", "([B)V",
-      (void *)android_media_MediaDrm_provideProvisionResponse },
+    { "provideProvisionResponseNative", "([B)Landroid/media/MediaDrm$Certificate;",
+      (void *)android_media_MediaDrm_provideProvisionResponseNative },
 
     { "getSecureStops", "()Ljava/util/List;",
       (void *)android_media_MediaDrm_getSecureStops },
@@ -1287,6 +1382,9 @@
 
     { "verifyNative", "(Landroid/media/MediaDrm;[B[B[B[B)Z",
       (void *)android_media_MediaDrm_verifyNative },
+
+    { "signRSANative", "(Landroid/media/MediaDrm;[BLjava/lang/String;[B[B)[B",
+      (void *)android_media_MediaDrm_signRSANative },
 };
 
 int register_android_media_Drm(JNIEnv *env) {
diff --git a/media/jni/android_media_MediaDrm.h b/media/jni/android_media_MediaDrm.h
index 620ad28..b7b8e5d 100644
--- a/media/jni/android_media_MediaDrm.h
+++ b/media/jni/android_media_MediaDrm.h
@@ -47,6 +47,8 @@
     void notify(DrmPlugin::EventType, int extra, const Parcel *obj);
     status_t setListener(const sp<DrmListener>& listener);
 
+    void disconnect();
+
 protected:
     virtual ~JDrm();
 
diff --git a/media/jni/android_mtp_MtpDatabase.cpp b/media/jni/android_mtp_MtpDatabase.cpp
index 7df56f4..f1949c0 100644
--- a/media/jni/android_mtp_MtpDatabase.cpp
+++ b/media/jni/android_mtp_MtpDatabase.cpp
@@ -850,6 +850,7 @@
                 result = malloc(exifdata->size);
                 if (result) {
                     memcpy(result, exifdata->data, exifdata->size);
+                    outThumbSize = exifdata->size;
                 }
             }
             exif_data_unref(exifdata);
diff --git a/media/lib/Android.mk b/media/lib/remotedisplay/Android.mk
similarity index 93%
rename from media/lib/Android.mk
rename to media/lib/remotedisplay/Android.mk
index 50799a6..ea1ac2b 100644
--- a/media/lib/Android.mk
+++ b/media/lib/remotedisplay/Android.mk
@@ -15,7 +15,7 @@
 #
 LOCAL_PATH := $(call my-dir)
 
-# the library
+# the remotedisplay library
 # ============================================================
 include $(CLEAR_VARS)
 
@@ -23,7 +23,7 @@
 LOCAL_MODULE_TAGS := optional
 
 LOCAL_SRC_FILES := \
-            $(call all-subdir-java-files) \
+            $(call all-java-files-under, java) \
             $(call all-aidl-files-under, java)
 
 include $(BUILD_JAVA_LIBRARY)
diff --git a/media/lib/README.txt b/media/lib/remotedisplay/README.txt
similarity index 99%
rename from media/lib/README.txt
rename to media/lib/remotedisplay/README.txt
index cade3df..5738dbe 100644
--- a/media/lib/README.txt
+++ b/media/lib/remotedisplay/README.txt
@@ -25,4 +25,3 @@
 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/remotedisplay/com.android.media.remotedisplay.xml
similarity index 100%
rename from media/lib/com.android.media.remotedisplay.xml
rename to media/lib/remotedisplay/com.android.media.remotedisplay.xml
diff --git a/media/lib/java/com/android/media/remotedisplay/RemoteDisplay.java b/media/lib/remotedisplay/java/com/android/media/remotedisplay/RemoteDisplay.java
similarity index 100%
rename from media/lib/java/com/android/media/remotedisplay/RemoteDisplay.java
rename to media/lib/remotedisplay/java/com/android/media/remotedisplay/RemoteDisplay.java
diff --git a/media/lib/java/com/android/media/remotedisplay/RemoteDisplayProvider.java b/media/lib/remotedisplay/java/com/android/media/remotedisplay/RemoteDisplayProvider.java
similarity index 100%
rename from media/lib/java/com/android/media/remotedisplay/RemoteDisplayProvider.java
rename to media/lib/remotedisplay/java/com/android/media/remotedisplay/RemoteDisplayProvider.java
diff --git a/media/lib/Android.mk b/media/lib/signer/Android.mk
similarity index 76%
copy from media/lib/Android.mk
copy to media/lib/signer/Android.mk
index 50799a6..4c3772f 100644
--- a/media/lib/Android.mk
+++ b/media/lib/signer/Android.mk
@@ -15,24 +15,23 @@
 #
 LOCAL_PATH := $(call my-dir)
 
-# the library
+# the mediadrm signer library
 # ============================================================
 include $(CLEAR_VARS)
 
-LOCAL_MODULE:= com.android.media.remotedisplay
+LOCAL_MODULE:= com.android.mediadrm.signer
 LOCAL_MODULE_TAGS := optional
 
 LOCAL_SRC_FILES := \
-            $(call all-subdir-java-files) \
-            $(call all-aidl-files-under, java)
+            $(call all-java-files-under, java)
 
-include $(BUILD_JAVA_LIBRARY)
+include $(BUILD_STATIC_JAVA_LIBRARY)
 
 
-# ====  com.android.media.remotedisplay.xml lib def  ========================
+# ====  com.android.mediadrm.signer.xml lib def  ========================
 include $(CLEAR_VARS)
 
-LOCAL_MODULE := com.android.media.remotedisplay.xml
+LOCAL_MODULE := com.android.mediadrm.signer.xml
 LOCAL_MODULE_TAGS := optional
 
 LOCAL_MODULE_CLASS := ETC
diff --git a/media/lib/signer/README.txt b/media/lib/signer/README.txt
new file mode 100644
index 0000000..362ab8e
--- /dev/null
+++ b/media/lib/signer/README.txt
@@ -0,0 +1,28 @@
+This library (com.android.mediadrm.signer.jar) is a shared java library
+containing classes required by unbundled apps running on devices that use
+the certficate provisioning and private key signing capabilities provided
+by the MediaDrm API.
+
+--- Rules of this library ---
+o This library is effectively a PUBLIC API for unbundled CAST receivers
+  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 exist? ---
+
+Unbundled apps cannot use internal platform classes.
+
+This library will eventually be replaced when the provisioned certificate-
+based signing 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.
+
diff --git a/media/lib/signer/com.android.mediadrm.signer.xml b/media/lib/signer/com.android.mediadrm.signer.xml
new file mode 100644
index 0000000..b5b1f09
--- /dev/null
+++ b/media/lib/signer/com.android.mediadrm.signer.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.drm.signer"
+            file="/system/framework/com.android.media.drm.signer.jar" />
+</permissions>
diff --git a/media/lib/signer/java/com/android/mediadrm/signer/MediaDrmSigner.java b/media/lib/signer/java/com/android/mediadrm/signer/MediaDrmSigner.java
new file mode 100644
index 0000000..0a2897f
--- /dev/null
+++ b/media/lib/signer/java/com/android/mediadrm/signer/MediaDrmSigner.java
@@ -0,0 +1,137 @@
+/*
+ * 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.mediadrm.signer;
+
+import android.media.MediaDrm;
+import android.media.DeniedByServerException;
+
+/**
+ * Provides certificate request generation, response handling and
+ * signing APIs
+ */
+public final class MediaDrmSigner {
+    private MediaDrmSigner() {}
+
+    /**
+     * Specify X.509 certificate type
+     */
+    public static final int CERTIFICATE_TYPE_X509 = MediaDrm.CERTIFICATE_TYPE_X509;
+
+    /**
+     * Contains the opaque data an app uses to request a certificate from a provisioning
+     * server
+     */
+    public final static class CertificateRequest {
+        private final MediaDrm.CertificateRequest mCertRequest;
+
+        CertificateRequest(MediaDrm.CertificateRequest certRequest) {
+            mCertRequest = certRequest;
+        }
+
+        /**
+         * Get the opaque message data
+         */
+        public byte[] getData() {
+            return mCertRequest.getData();
+        }
+
+        /**
+         * Get the default URL to use when sending the certificate request
+         * message to a server, if known. The app may prefer to use a different
+         * certificate server URL obtained from other sources.
+         */
+        public String getDefaultUrl() {
+            return mCertRequest.getDefaultUrl();
+        }
+    }
+
+    /**
+     * Contains the wrapped private key and public certificate data associated
+     * with a certificate.
+     */
+    public final static class Certificate {
+        private final MediaDrm.Certificate mCertificate;
+
+        Certificate(MediaDrm.Certificate certificate) {
+            mCertificate = certificate;
+        }
+
+        /**
+         * Get the wrapped private key data
+         */
+        public byte[] getWrappedPrivateKey() {
+            return mCertificate.getWrappedPrivateKey();
+        }
+
+        /**
+         * Get the PEM-encoded public certificate chain
+         */
+        public byte[] getContent() {
+            return mCertificate.getContent();
+        }
+    }
+
+    /**
+     * Generate a certificate request, specifying the certificate type
+     * and authority. The response received should be passed to
+     * provideCertificateResponse.
+     *
+     * @param drm the MediaDrm object
+     * @param certType Specifies the certificate type.
+     * @param certAuthority is passed to the certificate server to specify
+     * the chain of authority.
+     */
+    public static CertificateRequest getCertificateRequest(MediaDrm drm, int certType,
+            String certAuthority) {
+        return new CertificateRequest(drm.getCertificateRequest(certType, certAuthority));
+    }
+
+    /**
+     * Process a response from the provisioning server.  The response
+     * is obtained from an HTTP Post to the url provided by getCertificateRequest.
+     *
+     * The public X509 certificate chain and wrapped private key are returned
+     * in the returned Certificate objec.  The certificate chain is in BIO serialized
+     * PEM format.  The wrapped private key should be stored in application private
+     * storage, and used when invoking the signRSA method.
+     *
+     * @param drm the MediaDrm object
+     * @param response the opaque certificate response byte array to provide to the
+     * DRM engine plugin.
+     * @throws android.media.DeniedByServerException if the response indicates that the
+     * server rejected the request
+     */
+    public static Certificate provideCertificateResponse(MediaDrm drm, byte[] response)
+            throws DeniedByServerException {
+        return new Certificate(drm.provideCertificateResponse(response));
+    }
+
+    /**
+     * Sign data using an RSA key
+     *
+     * @param drm the MediaDrm object
+     * @param sessionId a sessionId obtained from openSession on the MediaDrm object
+     * @param algorithm the signing algorithm to use, e.g. "PKCS1-BlockType1"
+     * @param wrappedKey - the wrapped (encrypted) RSA private key obtained
+     * from provideCertificateResponse
+     * @param message the data for which a signature is to be computed
+     */
+    public static byte[] signRSA(MediaDrm drm, byte[] sessionId,
+            String algorithm, byte[] wrappedKey, byte[] message) {
+        return drm.signRSA(sessionId, algorithm, wrappedKey, message);
+    }
+}
diff --git a/native/android/sensor.cpp b/native/android/sensor.cpp
index 76c6eda..fb4de9e 100644
--- a/native/android/sensor.cpp
+++ b/native/android/sensor.cpp
@@ -153,3 +153,23 @@
 {
     return static_cast<Sensor const*>(sensor)->getMinDelay();
 }
+
+int ASensor_getFifoMaxEventCount(ASensor const* sensor)
+{
+    return static_cast<Sensor const*>(sensor)->getFifoMaxEventCount();
+}
+
+int ASensor_getFifoReservedEventCount(ASensor const* sensor)
+{
+    return static_cast<Sensor const*>(sensor)->getFifoReservedEventCount();
+}
+
+const char* ASensor_getStringType(ASensor const* sensor)
+{
+    return static_cast<Sensor const*>(sensor)->getStringType().string();
+}
+
+const char* ASensor_getRequiredPermission(ASensor const* sensor)
+{
+    return static_cast<Sensor const*>(sensor)->getRequiredPermission().string();
+}
diff --git a/packages/Keyguard/Android.mk b/packages/Keyguard/Android.mk
index f6f441d..1f2b5fb 100644
--- a/packages/Keyguard/Android.mk
+++ b/packages/Keyguard/Android.mk
@@ -18,8 +18,6 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-subdir-Iaidl-files)
 
-LOCAL_JAVA_LIBRARIES := services
-
 LOCAL_PACKAGE_NAME := Keyguard
 
 LOCAL_CERTIFICATE := platform
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
index c08880d..1e4ec42 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
@@ -167,9 +167,9 @@
 
     /**
      * Called when the screen turns off
-     * @param why {@link WindowManagerPolicy#OFF_BECAUSE_OF_USER},
-     *   {@link WindowManagerPolicy#OFF_BECAUSE_OF_TIMEOUT} or
-     *   {@link WindowManagerPolicy#OFF_BECAUSE_OF_PROX_SENSOR}.
+     * @param why either {@link WindowManagerPolicy#OFF_BECAUSE_OF_ADMIN},
+     * {@link WindowManagerPolicy#OFF_BECAUSE_OF_USER}, or
+     * {@link WindowManagerPolicy#OFF_BECAUSE_OF_TIMEOUT}.
      */
     public void onScreenTurnedOff(int why) { }
 }
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardViewMediator.java b/packages/Keyguard/src/com/android/keyguard/KeyguardViewMediator.java
index 4086f84..6d7eabc 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardViewMediator.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardViewMediator.java
@@ -577,9 +577,9 @@
 
     /**
      * Called to let us know the screen was turned off.
-     * @param why either {@link WindowManagerPolicy#OFF_BECAUSE_OF_USER},
-     *   {@link WindowManagerPolicy#OFF_BECAUSE_OF_TIMEOUT} or
-     *   {@link WindowManagerPolicy#OFF_BECAUSE_OF_PROX_SENSOR}.
+     * @param why either {@link WindowManagerPolicy#OFF_BECAUSE_OF_ADMIN},
+     * {@link WindowManagerPolicy#OFF_BECAUSE_OF_USER}, or
+     * {@link WindowManagerPolicy#OFF_BECAUSE_OF_TIMEOUT}.
      */
     public void onScreenTurnedOff(int why) {
         synchronized (this) {
@@ -611,8 +611,6 @@
             } else if (why == WindowManagerPolicy.OFF_BECAUSE_OF_TIMEOUT
                    || (why == WindowManagerPolicy.OFF_BECAUSE_OF_USER && !lockImmediately)) {
                 doKeyguardLaterLocked();
-            } else if (why == WindowManagerPolicy.OFF_BECAUSE_OF_PROX_SENSOR) {
-                // Do not enable the keyguard if the prox sensor forced the screen off.
             } else {
                 doKeyguardLocked(null);
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 604f4c3..76f8d88 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -1074,17 +1074,8 @@
     // A: Almost none! Only things coming from the system (package is "android") that also
     // have special "kind" tags marking them as relevant for setup (see below).
     protected boolean showNotificationEvenIfUnprovisioned(StatusBarNotification sbn) {
-        if ("android".equals(sbn.getPackageName())) {
-            if (sbn.getNotification().kind != null) {
-                for (String aKind : sbn.getNotification().kind) {
-                    // IME switcher, created by InputMethodManagerService
-                    if ("android.system.imeswitcher".equals(aKind)) return true;
-                    // OTA availability & errors, created by SystemUpdateService
-                    if ("android.system.update".equals(aKind)) return true;
-                }
-            }
-        }
-        return false;
+        return "android".equals(sbn.getPackageName())
+                && sbn.getNotification().extras.getBoolean(Notification.EXTRA_ALLOW_DURING_SETUP);
     }
 
     public boolean inKeyguardRestrictedInputMode() {
diff --git a/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java b/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java
index 757a7a2..a070e5e 100644
--- a/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java
+++ b/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java
@@ -348,12 +348,6 @@
 
         Point inSize = mCropView.getSourceDimensions();
 
-        // Due to rounding errors in the cropview renderer the edges can be slightly offset
-        // therefore we ensure that the boundaries are sanely defined
-        cropRect.left = Math.max(0, cropRect.left);
-        cropRect.right = Math.min(inSize.x, cropRect.right);
-        cropRect.top = Math.max(0, cropRect.top);
-        cropRect.bottom = Math.min(inSize.y, cropRect.bottom);
         int cropRotation = mCropView.getImageRotation();
         float cropScale = mCropView.getWidth() / (float) cropRect.width();
 
@@ -364,6 +358,13 @@
         rotatedInSize[0] = Math.abs(rotatedInSize[0]);
         rotatedInSize[1] = Math.abs(rotatedInSize[1]);
 
+        // Due to rounding errors in the cropview renderer the edges can be slightly offset
+        // therefore we ensure that the boundaries are sanely defined
+        cropRect.left = Math.max(0, cropRect.left);
+        cropRect.right = Math.min(rotatedInSize[0], cropRect.right);
+        cropRect.top = Math.max(0, cropRect.top);
+        cropRect.bottom = Math.min(rotatedInSize[1], cropRect.bottom);
+
         // ADJUST CROP WIDTH
         // Extend the crop all the way to the right, for parallax
         // (or all the way to the left, in RTL)
diff --git a/policy/src/com/android/internal/policy/impl/GlobalActions.java b/policy/src/com/android/internal/policy/impl/GlobalActions.java
index 4db7d4d..371fa0f 100644
--- a/policy/src/com/android/internal/policy/impl/GlobalActions.java
+++ b/policy/src/com/android/internal/policy/impl/GlobalActions.java
@@ -51,6 +51,7 @@
 import android.telephony.PhoneStateListener;
 import android.telephony.ServiceState;
 import android.telephony.TelephonyManager;
+import android.util.ArraySet;
 import android.util.Log;
 import android.util.TypedValue;
 import android.view.InputDevice;
@@ -83,6 +84,15 @@
 
     private static final boolean SHOW_SILENT_TOGGLE = true;
 
+    /* Valid settings for global actions keys.
+     * see config.xml config_globalActionList */
+    private static final String GLOBAL_ACTION_KEY_POWER = "power";
+    private static final String GLOBAL_ACTION_KEY_AIRPLANE = "airplane";
+    private static final String GLOBAL_ACTION_KEY_BUGREPORT = "bugreport";
+    private static final String GLOBAL_ACTION_KEY_SILENT = "silent";
+    private static final String GLOBAL_ACTION_KEY_USERS = "users";
+    private static final String GLOBAL_ACTION_KEY_SETTINGS = "settings";
+
     private final Context mContext;
     private final WindowManagerFuncs mWindowManagerFuncs;
     private final AudioManager mAudioManager;
@@ -173,11 +183,17 @@
         mDialog = createDialog();
         prepareDialog();
 
-        WindowManager.LayoutParams attrs = mDialog.getWindow().getAttributes();
-        attrs.setTitle("GlobalActions");
-        mDialog.getWindow().setAttributes(attrs);
-        mDialog.show();
-        mDialog.getWindow().getDecorView().setSystemUiVisibility(View.STATUS_BAR_DISABLE_EXPAND);
+        // If we only have 1 item and it's a simple press action, just do this action.
+        if (mAdapter.getCount() == 1
+                && mAdapter.getItem(0) instanceof SinglePressAction) {
+            ((SinglePressAction) mAdapter.getItem(0)).onPress();
+        } else {
+            WindowManager.LayoutParams attrs = mDialog.getWindow().getAttributes();
+            attrs.setTitle("GlobalActions");
+            mDialog.getWindow().setAttributes(attrs);
+            mDialog.show();
+            mDialog.getWindow().getDecorView().setSystemUiVisibility(View.STATUS_BAR_DISABLE_EXPAND);
+        }
     }
 
     /**
@@ -235,92 +251,36 @@
         onAirplaneModeChanged();
 
         mItems = new ArrayList<Action>();
+        String[] defaultActions = mContext.getResources().getStringArray(
+                com.android.internal.R.array.config_globalActionsList);
 
-        // first: power off
-        mItems.add(
-            new SinglePressAction(
-                    com.android.internal.R.drawable.ic_lock_power_off,
-                    R.string.global_action_power_off) {
-
-                public void onPress() {
-                    // shutdown by making sure radio and power are handled accordingly.
-                    mWindowManagerFuncs.shutdown(true);
-                }
-
-                public boolean onLongPress() {
-                    mWindowManagerFuncs.rebootSafeMode(true);
-                    return true;
-                }
-
-                public boolean showDuringKeyguard() {
-                    return true;
-                }
-
-                public boolean showBeforeProvisioning() {
-                    return true;
-                }
-            });
-
-        // next: airplane mode
-        mItems.add(mAirplaneModeOn);
-
-        // next: bug report, if enabled
-        if (Settings.Global.getInt(mContext.getContentResolver(),
-                Settings.Global.BUGREPORT_IN_POWER_MENU, 0) != 0 && isCurrentUserOwner()) {
-            mItems.add(
-                new SinglePressAction(com.android.internal.R.drawable.stat_sys_adb,
-                        R.string.global_action_bug_report) {
-
-                    public void onPress() {
-                        AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
-                        builder.setTitle(com.android.internal.R.string.bugreport_title);
-                        builder.setMessage(com.android.internal.R.string.bugreport_message);
-                        builder.setNegativeButton(com.android.internal.R.string.cancel, null);
-                        builder.setPositiveButton(com.android.internal.R.string.report,
-                                new DialogInterface.OnClickListener() {
-                                    @Override
-                                    public void onClick(DialogInterface dialog, int which) {
-                                        // Add a little delay before executing, to give the
-                                        // dialog a chance to go away before it takes a
-                                        // screenshot.
-                                        mHandler.postDelayed(new Runnable() {
-                                            @Override public void run() {
-                                                try {
-                                                    ActivityManagerNative.getDefault()
-                                                            .requestBugReport();
-                                                } catch (RemoteException e) {
-                                                }
-                                            }
-                                        }, 500);
-                                    }
-                                });
-                        AlertDialog dialog = builder.create();
-                        dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
-                        dialog.show();
-                    }
-
-                    public boolean onLongPress() {
-                        return false;
-                    }
-
-                    public boolean showDuringKeyguard() {
-                        return true;
-                    }
-
-                    public boolean showBeforeProvisioning() {
-                        return false;
-                    }
-                });
-        }
-
-        // last: silent mode
-        if (mShowSilentToggle) {
-            mItems.add(mSilentModeAction);
-        }
-
-        // one more thing: optionally add a list of users to switch to
-        if (SystemProperties.getBoolean("fw.power_user_switcher", false)) {
-            addUsersToMenu(mItems);
+        ArraySet<String> addedKeys = new ArraySet<String>();
+        for (int i = 0; i < defaultActions.length; i++) {
+            String actionKey = defaultActions[i];
+            if (addedKeys.contains(actionKey)) {
+                // If we already have added this, don't add it again.
+                continue;
+            }
+            if (GLOBAL_ACTION_KEY_POWER.equals(actionKey)) {
+                mItems.add(getPowerAction());
+            } else if (GLOBAL_ACTION_KEY_AIRPLANE.equals(actionKey)) {
+                mItems.add(mAirplaneModeOn);
+            } else if (GLOBAL_ACTION_KEY_BUGREPORT.equals(actionKey)
+                    && (Settings.Global.getInt(mContext.getContentResolver(),
+                        Settings.Global.BUGREPORT_IN_POWER_MENU, 0) != 0 && isCurrentUserOwner())) {
+                mItems.add(getBugReportAction());
+            } else if (GLOBAL_ACTION_KEY_SILENT.equals(actionKey) && mShowSilentToggle) {
+                mItems.add(mSilentModeAction);
+            } else if (GLOBAL_ACTION_KEY_USERS.equals(actionKey)
+                    && SystemProperties.getBoolean("fw.power_user_switcher", false)) {
+                addUsersToMenu(mItems);
+            } else if (GLOBAL_ACTION_KEY_SETTINGS.equals(actionKey)) {
+                mItems.add(getSettingsAction());
+            } else {
+                Log.e(TAG, "Invalid global action key " + actionKey);
+            }
+            // Add here so we don't add more than one.
+            addedKeys.add(actionKey);
         }
 
         mAdapter = new MyAdapter();
@@ -350,6 +310,105 @@
         return dialog;
     }
 
+    private Action getPowerAction() {
+        return new SinglePressAction(
+                com.android.internal.R.drawable.ic_lock_power_off,
+                R.string.global_action_power_off) {
+
+            public void onPress() {
+                // shutdown by making sure radio and power are handled accordingly.
+                mWindowManagerFuncs.shutdown(true);
+            }
+
+            public boolean onLongPress() {
+                mWindowManagerFuncs.rebootSafeMode(true);
+                return true;
+            }
+
+            public boolean showDuringKeyguard() {
+                return true;
+            }
+
+            public boolean showBeforeProvisioning() {
+                return true;
+            }
+        };
+    }
+
+    private Action getBugReportAction() {
+        return new SinglePressAction(com.android.internal.R.drawable.stat_sys_adb,
+                R.string.global_action_bug_report) {
+
+            public void onPress() {
+                AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
+                builder.setTitle(com.android.internal.R.string.bugreport_title);
+                builder.setMessage(com.android.internal.R.string.bugreport_message);
+                builder.setNegativeButton(com.android.internal.R.string.cancel, null);
+                builder.setPositiveButton(com.android.internal.R.string.report,
+                        new DialogInterface.OnClickListener() {
+                            @Override
+                            public void onClick(DialogInterface dialog, int which) {
+                                // Add a little delay before executing, to give the
+                                // dialog a chance to go away before it takes a
+                                // screenshot.
+                                mHandler.postDelayed(new Runnable() {
+                                    @Override public void run() {
+                                        try {
+                                            ActivityManagerNative.getDefault()
+                                                    .requestBugReport();
+                                        } catch (RemoteException e) {
+                                        }
+                                    }
+                                }, 500);
+                            }
+                        });
+                AlertDialog dialog = builder.create();
+                dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
+                dialog.show();
+            }
+
+            public boolean onLongPress() {
+                return false;
+            }
+
+            public boolean showDuringKeyguard() {
+                return true;
+            }
+
+            public boolean showBeforeProvisioning() {
+                return false;
+            }
+        };
+    }
+
+    private Action getSettingsAction() {
+        return new SinglePressAction(com.android.internal.R.drawable.ic_settings,
+                R.string.global_action_settings) {
+
+            @Override
+            public void onPress() {
+                Intent intent = new Intent(Settings.ACTION_SETTINGS);
+                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                mContext.startActivity(intent);
+            }
+
+            @Override
+            public boolean onLongPress() {
+                return false;
+            }
+
+            @Override
+            public boolean showDuringKeyguard() {
+                return true;
+            }
+
+            @Override
+            public boolean showBeforeProvisioning() {
+                return true;
+            }
+        };
+    }
+
     private UserInfo getCurrentUser() {
         try {
             return ActivityManagerNative.getDefault().getCurrentUser();
@@ -969,6 +1028,7 @@
                 mEnableAccessibilityController = null;
                 super.setCanceledOnTouchOutside(true);
             }
+
             super.onStart();
         }
 
diff --git a/policy/src/com/android/internal/policy/impl/PhoneLayoutInflater.java b/policy/src/com/android/internal/policy/impl/PhoneLayoutInflater.java
index 6bf4beb..968976b 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneLayoutInflater.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneLayoutInflater.java
@@ -26,7 +26,8 @@
 public class PhoneLayoutInflater extends LayoutInflater {
     private static final String[] sClassPrefixList = {
         "android.widget.",
-        "android.webkit."
+        "android.webkit.",
+        "android.app."
     };
     
     /**
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index 44fc1f8..c670b5c 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -38,10 +38,12 @@
 import com.android.internal.widget.ActionBarContextView;
 import com.android.internal.widget.ActionBarOverlayLayout;
 import com.android.internal.widget.ActionBarView;
+import com.android.internal.widget.SwipeDismissLayout;
 
 import android.app.KeyguardManager;
 import android.content.Context;
 import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
@@ -124,6 +126,7 @@
     TypedValue mFixedWidthMinor;
     TypedValue mFixedHeightMajor;
     TypedValue mFixedHeightMinor;
+    TypedValue mOutsetBottom;
 
     // This is the top-level view of the window, containing the window decor.
     private DecorView mDecor;
@@ -267,6 +270,20 @@
             // Remove the action bar feature if we have no title. No title dominates.
             removeFeature(FEATURE_ACTION_BAR);
         }
+
+        if ((features & (1 << FEATURE_ACTION_BAR)) != 0 && featureId == FEATURE_SWIPE_TO_DISMISS) {
+            throw new AndroidRuntimeException(
+                    "You cannot combine swipe dismissal and the action bar.");
+        }
+        if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0 && featureId == FEATURE_ACTION_BAR) {
+            throw new AndroidRuntimeException(
+                    "You cannot combine swipe dismissal and the action bar.");
+        }
+
+        if (featureId == FEATURE_INDETERMINATE_PROGRESS &&
+                getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) {
+            throw new AndroidRuntimeException("You cannot use indeterminate progress on a watch.");
+        }
         return super.requestFeature(featureId);
     }
 
@@ -2279,7 +2296,6 @@
                     } else {
                         h = 0;
                     }
-
                     if (h > 0) {
                         final int heightSize = MeasureSpec.getSize(heightMeasureSpec);
                         heightMeasureSpec = MeasureSpec.makeMeasureSpec(
@@ -2288,6 +2304,15 @@
                 }
             }
 
+            if (mOutsetBottom != null) {
+                int mode = MeasureSpec.getMode(heightMeasureSpec);
+                if (mode != MeasureSpec.UNSPECIFIED) {
+                    int outset = (int) mOutsetBottom.getDimension(metrics);
+                    int height = MeasureSpec.getSize(heightMeasureSpec);
+                    heightMeasureSpec = MeasureSpec.makeMeasureSpec(height + outset, mode);
+                }
+            }
+
             super.onMeasure(widthMeasureSpec, heightMeasureSpec);
 
             int width = getMeasuredWidth();
@@ -2838,6 +2863,10 @@
             requestFeature(FEATURE_ACTION_MODE_OVERLAY);
         }
 
+        if (a.getBoolean(com.android.internal.R.styleable.Window_windowSwipeToDismiss, false)) {
+            requestFeature(FEATURE_SWIPE_TO_DISMISS);
+        }
+
         if (a.getBoolean(com.android.internal.R.styleable.Window_windowFullscreen, false)) {
             setFlags(FLAG_FULLSCREEN, FLAG_FULLSCREEN & (~getForcedWindowFlags()));
         }
@@ -2890,6 +2919,10 @@
             a.getValue(com.android.internal.R.styleable.Window_windowFixedHeightMinor,
                     mFixedHeightMinor);
         }
+        if (a.hasValue(com.android.internal.R.styleable.Window_windowOutsetBottom)) {
+            if (mOutsetBottom == null) mOutsetBottom = new TypedValue();
+            a.getValue(com.android.internal.R.styleable.Window_windowOutsetBottom, mOutsetBottom);
+        }
 
         final Context context = getContext();
         final int targetSdk = context.getApplicationInfo().targetSdkVersion;
@@ -2964,7 +2997,9 @@
         int layoutResource;
         int features = getLocalFeatures();
         // System.out.println("Features: 0x" + Integer.toHexString(features));
-        if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) {
+        if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) {
+            layoutResource = com.android.internal.R.layout.screen_swipe_dismiss;
+        } else if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) {
             if (mIsFloating) {
                 TypedValue res = new TypedValue();
                 getContext().getTheme().resolveAttribute(
@@ -3034,6 +3069,10 @@
             }
         }
 
+        if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) {
+            registerSwipeCallbacks();
+        }
+
         // Remaining setup -- of background and title -- that only applies
         // to top-level windows.
         if (getContainer() == null) {
@@ -3390,6 +3429,47 @@
         return (mRightIconView = (ImageView)findViewById(com.android.internal.R.id.right_icon));
     }
 
+    private void registerSwipeCallbacks() {
+        SwipeDismissLayout swipeDismiss =
+                (SwipeDismissLayout) findViewById(com.android.internal.R.id.content);
+        swipeDismiss.setOnDismissedListener(new SwipeDismissLayout.OnDismissedListener() {
+            @Override
+            public void onDismissed(SwipeDismissLayout layout) {
+                dispatchOnWindowDismissed();
+            }
+        });
+        swipeDismiss.setOnSwipeProgressChangedListener(
+                new SwipeDismissLayout.OnSwipeProgressChangedListener() {
+                    private static final float ALPHA_DECREASE = 0.5f;
+                    private boolean mIsTranslucent = false;
+                    @Override
+                    public void onSwipeProgressChanged(
+                            SwipeDismissLayout layout, float progress, float translate) {
+                        WindowManager.LayoutParams newParams = getAttributes();
+                        newParams.x = (int) translate;
+                        newParams.alpha = 1 - (progress * ALPHA_DECREASE);
+                        setAttributes(newParams);
+
+                        int flags = 0;
+                        if (newParams.x == 0) {
+                            flags = FLAG_FULLSCREEN;
+                        } else {
+                            flags = FLAG_LAYOUT_NO_LIMITS;
+                        }
+                        setFlags(flags, FLAG_FULLSCREEN | FLAG_LAYOUT_NO_LIMITS);
+                    }
+
+                    @Override
+                    public void onSwipeCancelled(SwipeDismissLayout layout) {
+                        WindowManager.LayoutParams newParams = getAttributes();
+                        newParams.x = 0;
+                        newParams.alpha = 1;
+                        setAttributes(newParams);
+                        setFlags(FLAG_FULLSCREEN, FLAG_FULLSCREEN | FLAG_LAYOUT_NO_LIMITS);
+                    }
+                });
+    }
+
     /**
      * Helper method for calling the {@link Callback#onPanelClosed(int, Menu)}
      * callback. This method will grab whatever extra state is needed for the
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 70e4582..72f1e4f 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -232,7 +232,6 @@
     /** If true, hitting shift & menu will broadcast Intent.ACTION_BUG_REPORT */
     boolean mEnableShiftMenuBugReports = false;
 
-    boolean mHeadless;
     boolean mSafeMode;
     WindowState mStatusBar = null;
     int mStatusBarHeight;
@@ -285,6 +284,7 @@
     int mUserRotation = Surface.ROTATION_0;
     boolean mAccelerometerDefault;
 
+    boolean mSupportAutoRotation;
     int mAllowAllRotations = -1;
     boolean mCarDockEnablesAccelerometer;
     boolean mDeskDockEnablesAccelerometer;
@@ -593,13 +593,15 @@
      * screen is switched off.
      */
     boolean needSensorRunningLp() {
-        if (mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR
-                || mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR
-                || mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT
-                || mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE) {
-            // If the application has explicitly requested to follow the
-            // orientation, then we need to turn the sensor or.
-            return true;
+        if (mSupportAutoRotation) {
+            if (mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR
+                    || mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR
+                    || mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT
+                    || mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE) {
+                // If the application has explicitly requested to follow the
+                // orientation, then we need to turn the sensor on.
+                return true;
+            }
         }
         if ((mCarDockEnablesAccelerometer && mDockMode == Intent.EXTRA_DOCK_STATE_CAR) ||
                 (mDeskDockEnablesAccelerometer && (mDockMode == Intent.EXTRA_DOCK_STATE_DESK
@@ -620,7 +622,7 @@
             // still be turned off when the screen is off.)
             return false;
         }
-        return true;
+        return mSupportAutoRotation;
     }
 
     /*
@@ -666,7 +668,8 @@
     private void interceptPowerKeyDown(boolean handled) {
         mPowerKeyHandled = handled;
         if (!handled) {
-            mHandler.postDelayed(mPowerLongPress, ViewConfiguration.getGlobalActionKeyTimeout());
+            mHandler.postDelayed(mPowerLongPress,
+                    ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
         }
     }
 
@@ -705,9 +708,9 @@
         if (mKeyguardDelegate.isShowing()) {
             // Double the time it takes to take a screenshot from the keyguard
             return (long) (KEYGUARD_SCREENSHOT_CHORD_DELAY_MULTIPLIER *
-                    ViewConfiguration.getGlobalActionKeyTimeout());
+                    ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
         }
-        return ViewConfiguration.getGlobalActionKeyTimeout();
+        return ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout();
     }
 
     private void cancelPendingScreenshotChordAction() {
@@ -857,7 +860,6 @@
         mContext = context;
         mWindowManager = windowManager;
         mWindowManagerFuncs = windowManagerFuncs;
-        mHeadless = "1".equals(SystemProperties.get("ro.config.headless", "0"));
         mHandler = new PolicyHandler();
         mOrientationListener = new MyOrientationListener(mContext, mHandler);
         try {
@@ -886,6 +888,8 @@
         mBroadcastWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
                 "PhoneWindowManager.mBroadcastWakeLock");
         mEnableShiftMenuBugReports = "1".equals(SystemProperties.get("ro.debuggable"));
+        mSupportAutoRotation = mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_supportAutoRotation);
         mLidOpenRotation = readRotation(
                 com.android.internal.R.integer.config_lidOpenRotation);
         mCarDockRotation = readRotation(
@@ -983,9 +987,9 @@
 
         // Match current screen state.
         if (mPowerManager.isScreenOn()) {
-            screenTurningOn(null);
+            wakingUp(null);
         } else {
-            screenTurnedOff(WindowManagerPolicy.OFF_BECAUSE_OF_USER);
+            goingToSleep(WindowManagerPolicy.OFF_BECAUSE_OF_USER);
         }
     }
 
@@ -1676,7 +1680,8 @@
             return view.getParent() != null ? view : null;
         } catch (WindowManager.BadTokenException e) {
             // ignore
-            Log.w(TAG, appToken + " already running, starting window not displayed");
+            Log.w(TAG, appToken + " already running, starting window not displayed. " +
+                    e.getMessage());
         } catch (RuntimeException e) {
             // don't crash if something else bad happens, for example a
             // failure loading resources because we are loading from an app
@@ -2359,7 +2364,7 @@
     }
 
     private boolean interceptFallback(WindowState win, KeyEvent fallbackEvent, int policyFlags) {
-        int actions = interceptKeyBeforeQueueing(fallbackEvent, policyFlags, true);
+        int actions = interceptKeyBeforeQueueing(fallbackEvent, policyFlags);
         if ((actions & ACTION_PASS_TO_USER) != 0) {
             long delayMillis = interceptKeyBeforeDispatching(
                     win, fallbackEvent, policyFlags);
@@ -3416,8 +3421,9 @@
             }
 
             final boolean showWhenLocked = (attrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0;
+            final boolean dismissKeyguard = (attrs.flags & FLAG_DISMISS_KEYGUARD) != 0;
             if (appWindow) {
-                if (showWhenLocked) {
+                if (showWhenLocked || (dismissKeyguard && !isKeyguardSecure())) {
                     mAppsToBeHidden.remove(win.getAppToken());
                 } else {
                     mAppsToBeHidden.add(win.getAppToken());
@@ -3434,10 +3440,8 @@
                             mHideLockScreen = true;
                             mForceStatusBarFromKeyguard = false;
                         }
-                        if ((attrs.flags & FLAG_DISMISS_KEYGUARD) != 0
-                                && mDismissKeyguard == DISMISS_KEYGUARD_NONE) {
-                            if (DEBUG_LAYOUT) Slog.v(TAG,
-                                    "Setting mDismissKeyguard true by win " + win);
+                        if (dismissKeyguard && mDismissKeyguard == DISMISS_KEYGUARD_NONE) {
+                            if (DEBUG_LAYOUT) Slog.v(TAG, "Setting mDismissKeyguard true by win " + win);
                             mDismissKeyguard = mWinDismissingKeyguard == win ?
                                     DISMISS_KEYGUARD_CONTINUE : DISMISS_KEYGUARD_START;
                             mWinDismissingKeyguard = win;
@@ -3615,9 +3619,6 @@
 
     /** {@inheritDoc} */
     public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen) {
-        // do nothing if headless
-        if (mHeadless) return;
-
         // lid changed state
         final int newLidState = lidOpen ? LID_OPEN : LID_CLOSED;
         if (newLidState == mLidState) {
@@ -3802,12 +3803,13 @@
 
     /** {@inheritDoc} */
     @Override
-    public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn) {
+    public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
         if (!mSystemBooted) {
             // If we have not yet booted, don't let key events do anything.
             return 0;
         }
 
+        final boolean interactive = (policyFlags & FLAG_INTERACTIVE) != 0;
         final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
         final boolean canceled = event.isCanceled();
         final int keyCode = event.getKeyCode();
@@ -3819,21 +3821,20 @@
         // This will prevent any keys other than the power button from waking the screen
         // when the keyguard is hidden by another activity.
         final boolean keyguardActive = (mKeyguardDelegate == null ? false :
-                                            (isScreenOn ?
+                                            (interactive ?
                                                 mKeyguardDelegate.isShowingAndNotHidden() :
                                                 mKeyguardDelegate.isShowing()));
 
-        if (keyCode == KeyEvent.KEYCODE_POWER) {
+        if (keyCode == KeyEvent.KEYCODE_POWER
+                || keyCode == KeyEvent.KEYCODE_SLEEP
+                || keyCode == KeyEvent.KEYCODE_WAKEUP) {
             policyFlags |= WindowManagerPolicy.FLAG_WAKE;
         }
-        final boolean isWakeKey = (policyFlags & (WindowManagerPolicy.FLAG_WAKE
-                | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0;
 
         if (DEBUG_INPUT) {
             Log.d(TAG, "interceptKeyTq keycode=" + keyCode
-                    + " screenIsOn=" + isScreenOn + " keyguardActive=" + keyguardActive
-                    + " policyFlags=" + Integer.toHexString(policyFlags)
-                    + " isWakeKey=" + isWakeKey);
+                    + " interactive=" + interactive + " keyguardActive=" + keyguardActive
+                    + " policyFlags=" + Integer.toHexString(policyFlags));
         }
 
         if (down && (policyFlags & WindowManagerPolicy.FLAG_VIRTUAL) != 0
@@ -3841,24 +3842,19 @@
             performHapticFeedbackLw(null, HapticFeedbackConstants.VIRTUAL_KEY, false);
         }
 
-        // Basic policy based on screen state and keyguard.
-        // FIXME: This policy isn't quite correct.  We shouldn't care whether the screen
-        //        is on or off, really.  We should care about whether the device is in an
-        //        interactive state or is in suspend pretending to be "off".
-        //        The primary screen might be turned off due to proximity sensor or
-        //        because we are presenting media on an auxiliary screen or remotely controlling
-        //        the device some other way (which is why we have an exemption here for injected
-        //        events).
+        // Basic policy based on interactive state.
         int result;
-        if ((isScreenOn && !mHeadless) || (isInjected && !isWakeKey)) {
+        boolean isWakeKey = (policyFlags & (WindowManagerPolicy.FLAG_WAKE
+                | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0;
+        if (interactive || (isInjected && !isWakeKey)) {
             // When the screen is on or if the key is injected pass the key to the application.
             result = ACTION_PASS_TO_USER;
         } else {
             // When the screen is off and the key is not injected, determine whether
             // to wake the device but don't pass the key to the application.
             result = 0;
-            if (down && isWakeKey && isWakeKeyWhenScreenOff(keyCode)) {
-                result |= ACTION_WAKE_UP;
+            if (isWakeKey && (!down || !isWakeKeyWhenScreenOff(keyCode))) {
+                isWakeKey = false;
             }
         }
 
@@ -3875,7 +3871,7 @@
             case KeyEvent.KEYCODE_VOLUME_MUTE: {
                 if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
                     if (down) {
-                        if (isScreenOn && !mVolumeDownKeyTriggered
+                        if (interactive && !mVolumeDownKeyTriggered
                                 && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
                             mVolumeDownKeyTriggered = true;
                             mVolumeDownKeyTime = event.getDownTime();
@@ -3889,7 +3885,7 @@
                     }
                 } else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
                     if (down) {
-                        if (isScreenOn && !mVolumeUpKeyTriggered
+                        if (interactive && !mVolumeUpKeyTriggered
                                 && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
                             mVolumeUpKeyTriggered = true;
                             cancelPendingPowerKeyAction();
@@ -3957,7 +3953,7 @@
                             Log.w(TAG, "ITelephony threw RemoteException", ex);
                         }
                     }
-                    interceptPowerKeyDown(!isScreenOn || hungUp);
+                    interceptPowerKeyDown(!interactive || hungUp);
                 } else {
                     if (interceptPowerKeyUp(canceled)) {
                         if ((mEndcallBehavior
@@ -3968,7 +3964,8 @@
                         }
                         if ((mEndcallBehavior
                                 & Settings.System.END_BUTTON_BEHAVIOR_SLEEP) != 0) {
-                            result = (result & ~ACTION_WAKE_UP) | ACTION_GO_TO_SLEEP;
+                            mPowerManager.goToSleep(event.getEventTime());
+                            isWakeKey = false;
                         }
                     }
                 }
@@ -3978,9 +3975,9 @@
             case KeyEvent.KEYCODE_POWER: {
                 result &= ~ACTION_PASS_TO_USER;
                 if (down) {
-                    mImmersiveModeConfirmation.onPowerKeyDown(isScreenOn, event.getDownTime(),
+                    mImmersiveModeConfirmation.onPowerKeyDown(interactive, event.getDownTime(),
                             isImmersiveMode(mLastSystemUiFlags));
-                    if (isScreenOn && !mPowerKeyTriggered
+                    if (interactive && !mPowerKeyTriggered
                             && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
                         mPowerKeyTriggered = true;
                         mPowerKeyTime = event.getDownTime();
@@ -4006,19 +4003,32 @@
                             Log.w(TAG, "ITelephony threw RemoteException", ex);
                         }
                     }
-                    interceptPowerKeyDown(!isScreenOn || hungUp
+                    interceptPowerKeyDown(!interactive || hungUp
                             || mVolumeDownKeyTriggered || mVolumeUpKeyTriggered);
                 } else {
                     mPowerKeyTriggered = false;
                     cancelPendingScreenshotChordAction();
                     if (interceptPowerKeyUp(canceled || mPendingPowerKeyUpCanceled)) {
-                        result = (result & ~ACTION_WAKE_UP) | ACTION_GO_TO_SLEEP;
+                        mPowerManager.goToSleep(event.getEventTime());
+                        isWakeKey = false;
                     }
                     mPendingPowerKeyUpCanceled = false;
                 }
                 break;
             }
 
+            case KeyEvent.KEYCODE_SLEEP: {
+                result &= ~ACTION_PASS_TO_USER;
+                mPowerManager.goToSleep(event.getEventTime());
+                isWakeKey = false;
+                break;
+            }
+
+            case KeyEvent.KEYCODE_WAKEUP: {
+                result &= ~ACTION_PASS_TO_USER;
+                break;
+            }
+
             case KeyEvent.KEYCODE_MEDIA_PLAY:
             case KeyEvent.KEYCODE_MEDIA_PAUSE:
             case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
@@ -4082,6 +4092,10 @@
                 break;
             }
         }
+
+        if (isWakeKey) {
+            mPowerManager.wakeUp(event.getEventTime());
+        }
         return result;
     }
 
@@ -4122,15 +4136,12 @@
 
     /** {@inheritDoc} */
     @Override
-    public int interceptMotionBeforeQueueingWhenScreenOff(int policyFlags) {
-        int result = 0;
-
-        final boolean isWakeMotion = (policyFlags
-                & (WindowManagerPolicy.FLAG_WAKE | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0;
-        if (isWakeMotion) {
-            result |= ACTION_WAKE_UP;
-        }
-        return result;
+    public int interceptWakeMotionBeforeQueueing(long whenNanos, int policyFlags) {
+        // We already know this is a wake motion so just wake up.
+        // Note that we would observe policyFlags containing
+        // FLAG_WAKE and FLAG_INTERACTIVE here.
+        mPowerManager.wakeUp(whenNanos / 1000000);
+        return 0;
     }
 
     void dispatchMediaKeyWithWakeLock(KeyEvent event) {
@@ -4265,7 +4276,7 @@
     }
 
     @Override
-    public void screenTurnedOff(int why) {
+    public void goingToSleep(int why) {
         EventLog.writeEvent(70000, 0);
         synchronized (mLock) {
             mScreenOnEarly = false;
@@ -4281,7 +4292,7 @@
     }
 
     @Override
-    public void screenTurningOn(final ScreenOnListener screenOnListener) {
+    public void wakingUp(final ScreenOnListener screenOnListener) {
         EventLog.writeEvent(70000, 1);
         if (false) {
             RuntimeException here = new RuntimeException("here");
@@ -4492,6 +4503,10 @@
             } else if (orientation == ActivityInfo.SCREEN_ORIENTATION_LOCKED) {
                 // Application just wants to remain locked in the last rotation.
                 preferredRotation = lastRotation;
+            } else if (!mSupportAutoRotation) {
+                // If we don't support auto-rotation then bail out here and ignore
+                // the sensor and any rotation lock settings.
+                preferredRotation = -1;
             } else if ((mUserRotationMode == WindowManagerPolicy.USER_ROTATION_FREE
                             && (orientation == ActivityInfo.SCREEN_ORIENTATION_USER
                                     || orientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
@@ -4676,10 +4691,9 @@
     /** {@inheritDoc} */
     @Override
     public void systemReady() {
-        if (!mHeadless) {
-            mKeyguardDelegate = new KeyguardServiceDelegate(mContext, null);
-            mKeyguardDelegate.onSystemReady();
-        }
+        mKeyguardDelegate = new KeyguardServiceDelegate(mContext, null);
+        mKeyguardDelegate.onSystemReady();
+
         synchronized (mLock) {
             updateOrientationListenerLp();
             mSystemReady = true;
@@ -4706,11 +4720,14 @@
 
     /** {@inheritDoc} */
     public void showBootMessage(final CharSequence msg, final boolean always) {
-        if (mHeadless) return;
         mHandler.post(new Runnable() {
             @Override public void run() {
                 if (mBootMsgDialog == null) {
-                    mBootMsgDialog = new ProgressDialog(mContext) {
+                    int theme =  mContext.getPackageManager().hasSystemFeature(
+                            PackageManager.FEATURE_WATCH) ?
+                            com.android.internal.R.style.Theme_Micro_Dialog_Alert : 0;
+
+                    mBootMsgDialog = new ProgressDialog(mContext, theme) {
                         // This dialog will consume all events coming in to
                         // it, to avoid it trying to do things too early in boot.
                         @Override public boolean dispatchKeyEvent(KeyEvent event) {
@@ -5303,6 +5320,7 @@
             pw.print(prefix); pw.print("mLastFocusNeedsMenu=");
                     pw.println(mLastFocusNeedsMenu);
         }
+        pw.print(prefix); pw.print("mSupportAutoRotation="); pw.println(mSupportAutoRotation);
         pw.print(prefix); pw.print("mUiMode="); pw.print(mUiMode);
                 pw.print(" mDockMode="); pw.print(mDockMode);
                 pw.print(" mCarDockRotation="); pw.print(mCarDockRotation);
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceDelegate.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceDelegate.java
index 1357462..e5af716 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceDelegate.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardServiceDelegate.java
@@ -109,6 +109,9 @@
         if (!context.bindServiceAsUser(intent, mKeyguardConnection,
                 Context.BIND_AUTO_CREATE, UserHandle.OWNER)) {
             if (DEBUG) Log.v(TAG, "*** Keyguard: can't bind to " + KEYGUARD_CLASS);
+            mKeyguardState.showing = false;
+            mKeyguardState.showingAndNotHidden = false;
+            mKeyguardState.secure = false;
         } else {
             if (DEBUG) Log.v(TAG, "*** Keyguard started");
         }
diff --git a/preloaded-classes b/preloaded-classes
index b60a379..5bdd6593 100644
--- a/preloaded-classes
+++ b/preloaded-classes
@@ -3,56 +3,19 @@
 # MIN_LOAD_TIME_MICROS=1250
 # MIN_PROCESSES=10
 android.R$styleable
-android.accounts.Account
-android.accounts.Account$1
-android.accounts.AccountManager
-android.accounts.AccountManager$12
-android.accounts.AccountManager$13
-android.accounts.AccountManager$6
-android.accounts.AccountManager$AmsTask
-android.accounts.AccountManager$AmsTask$1
-android.accounts.AccountManager$AmsTask$Response
-android.accounts.AccountManagerFuture
-android.accounts.IAccountManager
-android.accounts.IAccountManager$Stub
-android.accounts.IAccountManager$Stub$Proxy
-android.accounts.IAccountManagerResponse
-android.accounts.IAccountManagerResponse$Stub
-android.accounts.OnAccountsUpdateListener
 android.animation.Animator
-android.animation.Animator$AnimatorListener
-android.animation.AnimatorListenerAdapter
-android.animation.AnimatorSet
-android.animation.AnimatorSet$AnimatorSetListener
-android.animation.AnimatorSet$Builder
-android.animation.AnimatorSet$DependencyListener
-android.animation.AnimatorSet$Node
-android.animation.FloatEvaluator
-android.animation.FloatKeyframeSet
-android.animation.IntEvaluator
-android.animation.IntKeyframeSet
-android.animation.Keyframe
-android.animation.Keyframe$FloatKeyframe
-android.animation.Keyframe$IntKeyframe
-android.animation.KeyframeSet
-android.animation.LayoutTransition$TransitionListener
-android.animation.ObjectAnimator
+android.animation.LayoutTransition
 android.animation.PropertyValuesHolder
-android.animation.PropertyValuesHolder$FloatPropertyValuesHolder
-android.animation.PropertyValuesHolder$IntPropertyValuesHolder
 android.animation.TimeInterpolator
-android.animation.TypeEvaluator
 android.animation.ValueAnimator
-android.animation.ValueAnimator$AnimationHandler
 android.app.ActionBar
-android.app.ActionBar$LayoutParams
 android.app.Activity
 android.app.Activity$1
+android.app.Activity$ManagedCursor
+android.app.Activity$ManagedDialog
+android.app.Activity$NonConfigurationInstances
+android.app.Activity$TranslucentConversionListener
 android.app.ActivityManager
-android.app.ActivityManager$MemoryInfo
-android.app.ActivityManager$MemoryInfo$1
-android.app.ActivityManager$RunningAppProcessInfo
-android.app.ActivityManager$RunningAppProcessInfo$1
 android.app.ActivityManagerNative
 android.app.ActivityManagerNative$1
 android.app.ActivityManagerProxy
@@ -64,33 +27,34 @@
 android.app.ActivityThread$ApplicationThread
 android.app.ActivityThread$BindServiceData
 android.app.ActivityThread$ContextCleanupInfo
+android.app.ActivityThread$CreateBackupAgentData
 android.app.ActivityThread$CreateServiceData
 android.app.ActivityThread$DropBoxReporter
 android.app.ActivityThread$DumpComponentInfo
+android.app.ActivityThread$DumpHeapData
 android.app.ActivityThread$EventLoggingReporter
 android.app.ActivityThread$GcIdler
 android.app.ActivityThread$H
 android.app.ActivityThread$Idler
+android.app.ActivityThread$NewIntentData
 android.app.ActivityThread$Profiler
+android.app.ActivityThread$ProfilerControlData
 android.app.ActivityThread$ProviderClientRecord
 android.app.ActivityThread$ProviderKey
 android.app.ActivityThread$ProviderRefCount
 android.app.ActivityThread$ReceiverData
+android.app.ActivityThread$RequestAssistContextExtras
 android.app.ActivityThread$ResultData
 android.app.ActivityThread$ServiceArgsData
 android.app.ActivityThread$StopInfo
-android.app.AlertDialog
-android.app.AlertDialog$Builder
-android.app.AppGlobals
+android.app.ActivityThread$UpdateCompatibilityData
+android.app.ActivityView
+android.app.AppOpsManager
 android.app.Application
-android.app.Application$ActivityLifecycleCallbacks
 android.app.ApplicationErrorReport$CrashInfo
 android.app.ApplicationLoaders
 android.app.ApplicationPackageManager
-android.app.ApplicationPackageManager$ResourceName
 android.app.ApplicationThreadNative
-android.app.BackStackRecord
-android.app.BackStackRecord$Op
 android.app.ContextImpl
 android.app.ContextImpl$1
 android.app.ContextImpl$10
@@ -127,6 +91,11 @@
 android.app.ContextImpl$39
 android.app.ContextImpl$4
 android.app.ContextImpl$40
+android.app.ContextImpl$41
+android.app.ContextImpl$42
+android.app.ContextImpl$43
+android.app.ContextImpl$44
+android.app.ContextImpl$45
 android.app.ContextImpl$5
 android.app.ContextImpl$6
 android.app.ContextImpl$7
@@ -136,79 +105,44 @@
 android.app.ContextImpl$ServiceFetcher
 android.app.ContextImpl$StaticServiceFetcher
 android.app.Dialog
-android.app.Dialog$1
-android.app.Dialog$ListenersHandler
 android.app.Fragment
-android.app.FragmentBreadCrumbs
-android.app.FragmentBreadCrumbs$1
 android.app.FragmentContainer
 android.app.FragmentManager
-android.app.FragmentManager$BackStackEntry
-android.app.FragmentManager$OnBackStackChangedListener
 android.app.FragmentManagerImpl
-android.app.FragmentManagerImpl$1
-android.app.FragmentTransaction
+android.app.IActivityContainer
 android.app.IActivityManager
 android.app.IActivityManager$ContentProviderHolder
 android.app.IActivityManager$ContentProviderHolder$1
-android.app.IAlarmManager
-android.app.IAlarmManager$Stub
-android.app.IAlarmManager$Stub$Proxy
 android.app.IApplicationThread
 android.app.IInstrumentationWatcher
 android.app.IInstrumentationWatcher$Stub
-android.app.INotificationManager
-android.app.INotificationManager$Stub
-android.app.INotificationManager$Stub$Proxy
-android.app.ISearchManager
-android.app.ISearchManager$Stub
-android.app.ISearchManager$Stub$Proxy
 android.app.IServiceConnection
-android.app.IServiceConnection$Stub
-android.app.ITransientNotification
-android.app.ITransientNotification$Stub
 android.app.IUiAutomationConnection
 android.app.IUiAutomationConnection$Stub
 android.app.Instrumentation
+android.app.Instrumentation$ActivityResult
 android.app.IntentReceiverLeaked
-android.app.IntentService
-android.app.IntentService$ServiceHandler
-android.app.ListActivity
-android.app.ListActivity$1
-android.app.ListActivity$2
 android.app.LoadedApk
+android.app.LoadedApk$1
 android.app.LoadedApk$ReceiverDispatcher
-android.app.LoadedApk$ReceiverDispatcher$Args
-android.app.LoadedApk$ReceiverDispatcher$InnerReceiver
 android.app.LoadedApk$ServiceDispatcher
-android.app.LoadedApk$ServiceDispatcher$ConnectionInfo
-android.app.LoadedApk$ServiceDispatcher$DeathMonitor
-android.app.LoadedApk$ServiceDispatcher$InnerConnection
-android.app.LoadedApk$ServiceDispatcher$RunConnection
 android.app.LoadedApk$WarningContextClassLoader
 android.app.LoaderManager
 android.app.LoaderManagerImpl
 android.app.NativeActivity
-android.app.Notification
-android.app.Notification$1
-android.app.Notification$Builder
-android.app.NotificationManager
 android.app.OnActivityPausedListener
 android.app.PendingIntent
-android.app.PendingIntent$1
 android.app.QueuedWork
 android.app.ReceiverRestrictedContext
+android.app.RemoteServiceException
+android.app.ResourcesManager
 android.app.ResultInfo
-android.app.ResultInfo$1
 android.app.Service
 android.app.ServiceConnectionLeaked
 android.app.SharedPreferencesImpl
-android.app.SharedPreferencesImpl$1
-android.app.SharedPreferencesImpl$2
-android.app.SharedPreferencesImpl$EditorImpl
-android.app.SharedPreferencesImpl$EditorImpl$1
-android.app.SharedPreferencesImpl$EditorImpl$2
-android.app.SharedPreferencesImpl$MemoryCommitResult
+android.app.TaskStackBuilder
+android.app.WallpaperManager
+android.app.backup.BackupAgent
 android.app.backup.BackupDataInput
 android.app.backup.BackupDataInput$EntityHeader
 android.app.backup.BackupDataOutput
@@ -216,64 +150,33 @@
 android.app.backup.BackupHelperDispatcher$Header
 android.app.backup.FileBackupHelperBase
 android.app.backup.FullBackup
-android.appwidget.AppWidgetManager
-android.appwidget.AppWidgetProvider
-android.bluetooth.BluetoothUuid
-android.content.AbstractThreadedSyncAdapter
-android.content.AbstractThreadedSyncAdapter$ISyncAdapterImpl
-android.content.AbstractThreadedSyncAdapter$SyncThread
 android.content.BroadcastReceiver
 android.content.BroadcastReceiver$PendingResult
+android.content.ClipData
+android.content.ClipData$Item
+android.content.ClipDescription
 android.content.ComponentCallbacks
 android.content.ComponentCallbacks2
 android.content.ComponentName
 android.content.ComponentName$1
 android.content.ContentProvider
-android.content.ContentProvider$Transport
-android.content.ContentProviderClient
 android.content.ContentProviderNative
-android.content.ContentProviderProxy
-android.content.ContentProviderResult
 android.content.ContentResolver
-android.content.ContentResolver$CursorWrapperInner
-android.content.ContentResolver$ParcelFileDescriptorInner
-android.content.ContentUris
-android.content.ContentValues
-android.content.ContentValues$1
 android.content.Context
 android.content.ContextWrapper
 android.content.DialogInterface
 android.content.DialogInterface$OnCancelListener
-android.content.DialogInterface$OnClickListener
 android.content.DialogInterface$OnDismissListener
 android.content.IContentProvider
-android.content.IContentService
-android.content.IContentService$Stub
-android.content.IContentService$Stub$Proxy
 android.content.IIntentReceiver
-android.content.IIntentReceiver$Stub
 android.content.IIntentSender
-android.content.IIntentSender$Stub
-android.content.IIntentSender$Stub$Proxy
-android.content.ISyncAdapter
-android.content.ISyncAdapter$Stub
-android.content.ISyncContext
-android.content.ISyncContext$Stub
-android.content.ISyncContext$Stub$Proxy
 android.content.Intent
 android.content.Intent$1
 android.content.IntentFilter
-android.content.IntentFilter$1
+android.content.IntentSender
+android.content.IntentSender$SendIntentException
 android.content.ServiceConnection
 android.content.SharedPreferences
-android.content.SharedPreferences$Editor
-android.content.SharedPreferences$OnSharedPreferenceChangeListener
-android.content.SyncContext
-android.content.SyncResult
-android.content.SyncResult$1
-android.content.SyncStats
-android.content.SyncStats$1
-android.content.UriMatcher
 android.content.pm.ActivityInfo
 android.content.pm.ActivityInfo$1
 android.content.pm.ApplicationInfo
@@ -300,13 +203,10 @@
 android.content.pm.ProviderInfo
 android.content.pm.ProviderInfo$1
 android.content.pm.ResolveInfo
-android.content.pm.ResolveInfo$1
 android.content.pm.ServiceInfo
 android.content.pm.ServiceInfo$1
 android.content.pm.Signature
 android.content.pm.Signature$1
-android.content.pm.UserInfo
-android.content.pm.UserInfo$1
 android.content.res.AssetFileDescriptor
 android.content.res.AssetFileDescriptor$1
 android.content.res.AssetManager
@@ -316,81 +216,37 @@
 android.content.res.CompatibilityInfo
 android.content.res.CompatibilityInfo$1
 android.content.res.CompatibilityInfo$2
+android.content.res.CompatibilityInfo$Translator
 android.content.res.Configuration
 android.content.res.Configuration$1
 android.content.res.ObbInfo
 android.content.res.ObbInfo$1
 android.content.res.ObbScanner
 android.content.res.Resources
+android.content.res.Resources$NotFoundException
 android.content.res.Resources$Theme
+android.content.res.ResourcesKey
 android.content.res.StringBlock
-android.content.res.StringBlock$StyleIDs
 android.content.res.TypedArray
 android.content.res.XmlBlock
 android.content.res.XmlBlock$Parser
 android.content.res.XmlResourceParser
-android.database.AbstractCursor
-android.database.AbstractCursor$SelfContentObserver
-android.database.AbstractWindowedCursor
-android.database.BulkCursorDescriptor
-android.database.BulkCursorDescriptor$1
-android.database.BulkCursorNative
-android.database.BulkCursorProxy
-android.database.BulkCursorToCursorAdaptor
 android.database.CharArrayBuffer
-android.database.ContentObservable
-android.database.ContentObserver
-android.database.ContentObserver$NotificationRunnable
-android.database.ContentObserver$Transport
-android.database.CrossProcessCursor
-android.database.CrossProcessCursorWrapper
 android.database.Cursor
-android.database.CursorToBulkCursorAdaptor
-android.database.CursorToBulkCursorAdaptor$ContentObserverProxy
 android.database.CursorWindow
-android.database.CursorWindow$1
-android.database.CursorWrapper
-android.database.DataSetObservable
-android.database.DataSetObserver
 android.database.DatabaseErrorHandler
 android.database.DatabaseUtils
-android.database.DefaultDatabaseErrorHandler
-android.database.IBulkCursor
-android.database.IContentObserver
-android.database.IContentObserver$Stub
-android.database.IContentObserver$Stub$Proxy
-android.database.MatrixCursor
-android.database.Observable
-android.database.sqlite.DatabaseObjectNotClosedException
 android.database.sqlite.SQLiteClosable
 android.database.sqlite.SQLiteConnection
 android.database.sqlite.SQLiteConnection$Operation
-android.database.sqlite.SQLiteConnection$OperationLog
-android.database.sqlite.SQLiteConnection$PreparedStatement
-android.database.sqlite.SQLiteConnection$PreparedStatementCache
-android.database.sqlite.SQLiteConnectionPool
-android.database.sqlite.SQLiteConnectionPool$AcquiredConnectionStatus
-android.database.sqlite.SQLiteConnectionPool$ConnectionWaiter
-android.database.sqlite.SQLiteCursor
-android.database.sqlite.SQLiteCursorDriver
 android.database.sqlite.SQLiteCustomFunction
 android.database.sqlite.SQLiteDatabase
-android.database.sqlite.SQLiteDatabase$1
-android.database.sqlite.SQLiteDatabase$2
-android.database.sqlite.SQLiteDatabaseConfiguration
+android.database.sqlite.SQLiteDatabase$CursorFactory
 android.database.sqlite.SQLiteDebug
 android.database.sqlite.SQLiteDebug$DbStats
 android.database.sqlite.SQLiteDebug$PagerStats
-android.database.sqlite.SQLiteDirectCursorDriver
 android.database.sqlite.SQLiteGlobal
-android.database.sqlite.SQLiteOpenHelper
-android.database.sqlite.SQLiteProgram
-android.database.sqlite.SQLiteQuery
 android.database.sqlite.SQLiteQueryBuilder
-android.database.sqlite.SQLiteSession
-android.database.sqlite.SQLiteSession$Transaction
-android.database.sqlite.SQLiteStatement
-android.database.sqlite.SQLiteStatementInfo
 android.ddm.DdmHandleAppName
 android.ddm.DdmHandleExit
 android.ddm.DdmHandleHeap
@@ -400,12 +256,11 @@
 android.ddm.DdmHandleThread
 android.ddm.DdmHandleViewDebug
 android.ddm.DdmRegister
-android.drm.DrmManagerClient
+android.debug.JNITest
 android.emoji.EmojiFactory
 android.graphics.AvoidXfermode
 android.graphics.Bitmap
 android.graphics.Bitmap$1
-android.graphics.Bitmap$2
 android.graphics.Bitmap$BitmapFinalizer
 android.graphics.Bitmap$Config
 android.graphics.BitmapFactory
@@ -436,7 +291,6 @@
 android.graphics.MaskFilter
 android.graphics.Matrix
 android.graphics.Matrix$1
-android.graphics.Matrix$ScaleToFit
 android.graphics.Movie
 android.graphics.NinePatch
 android.graphics.Paint
@@ -448,8 +302,6 @@
 android.graphics.Paint$Style
 android.graphics.PaintFlagsDrawFilter
 android.graphics.Path
-android.graphics.Path$Direction
-android.graphics.Path$FillType
 android.graphics.PathDashPathEffect
 android.graphics.PathEffect
 android.graphics.PathMeasure
@@ -474,24 +326,20 @@
 android.graphics.Region$Op
 android.graphics.RegionIterator
 android.graphics.Shader
-android.graphics.Shader$TileMode
 android.graphics.SumPathEffect
 android.graphics.SurfaceTexture
-android.graphics.SurfaceTexture$OnFrameAvailableListener
 android.graphics.SweepGradient
 android.graphics.TableMaskFilter
-android.graphics.TemporaryBuffer
 android.graphics.Typeface
 android.graphics.Xfermode
 android.graphics.YuvImage
 android.graphics.drawable.Animatable
+android.graphics.drawable.AnimatedRotateDrawable
 android.graphics.drawable.AnimationDrawable
-android.graphics.drawable.AnimationDrawable$AnimationState
 android.graphics.drawable.BitmapDrawable
-android.graphics.drawable.BitmapDrawable$BitmapState
 android.graphics.drawable.ClipDrawable
-android.graphics.drawable.ClipDrawable$ClipState
 android.graphics.drawable.ColorDrawable
+android.graphics.drawable.ColorDrawable$1
 android.graphics.drawable.ColorDrawable$ColorState
 android.graphics.drawable.Drawable
 android.graphics.drawable.Drawable$Callback
@@ -499,38 +347,33 @@
 android.graphics.drawable.DrawableContainer
 android.graphics.drawable.DrawableContainer$DrawableContainerState
 android.graphics.drawable.GradientDrawable
-android.graphics.drawable.GradientDrawable$1
-android.graphics.drawable.GradientDrawable$GradientState
-android.graphics.drawable.GradientDrawable$Orientation
+android.graphics.drawable.InsetDrawable
 android.graphics.drawable.LayerDrawable
 android.graphics.drawable.LayerDrawable$ChildDrawable
 android.graphics.drawable.LayerDrawable$LayerState
+android.graphics.drawable.LevelListDrawable
 android.graphics.drawable.NinePatchDrawable
+android.graphics.drawable.NinePatchDrawable$1
 android.graphics.drawable.NinePatchDrawable$NinePatchState
 android.graphics.drawable.RotateDrawable
-android.graphics.drawable.RotateDrawable$RotateState
 android.graphics.drawable.ScaleDrawable
-android.graphics.drawable.ScaleDrawable$ScaleState
-android.graphics.drawable.ShapeDrawable
-android.graphics.drawable.ShapeDrawable$ShapeState
 android.graphics.drawable.StateListDrawable
+android.graphics.drawable.StateListDrawable$1
 android.graphics.drawable.StateListDrawable$StateListState
 android.graphics.drawable.TransitionDrawable
 android.graphics.drawable.TransitionDrawable$TransitionState
-android.graphics.drawable.shapes.RectShape
-android.graphics.drawable.shapes.RoundRectShape
-android.graphics.drawable.shapes.Shape
+android.graphics.pdf.PdfDocument
 android.hardware.Camera
 android.hardware.Camera$CameraInfo
 android.hardware.Camera$Face
-android.hardware.Sensor
-android.hardware.SensorEvent
-android.hardware.SensorEventListener
 android.hardware.SensorManager
 android.hardware.SerialPort
 android.hardware.SystemSensorManager
 android.hardware.SystemSensorManager$BaseEventQueue
+android.hardware.camera2.CameraMetadata
+android.hardware.camera2.impl.CameraMetadataNative
 android.hardware.display.DisplayManager
+android.hardware.display.DisplayManager$DisplayListener
 android.hardware.display.DisplayManagerGlobal
 android.hardware.display.DisplayManagerGlobal$DisplayManagerCallback
 android.hardware.display.IDisplayManager
@@ -538,193 +381,100 @@
 android.hardware.display.IDisplayManager$Stub$Proxy
 android.hardware.display.IDisplayManagerCallback
 android.hardware.display.IDisplayManagerCallback$Stub
-android.hardware.input.IInputDevicesChangedListener
-android.hardware.input.IInputDevicesChangedListener$Stub
-android.hardware.input.IInputManager
-android.hardware.input.IInputManager$Stub
-android.hardware.input.IInputManager$Stub$Proxy
-android.hardware.input.InputManager
-android.hardware.input.InputManager$InputDevicesChangedListener
 android.hardware.usb.UsbDevice
 android.hardware.usb.UsbDeviceConnection
 android.hardware.usb.UsbRequest
 android.inputmethodservice.ExtractEditText
-android.location.GpsSatellite
-android.location.GpsStatus
-android.location.GpsStatus$1
-android.location.ILocationManager
-android.location.ILocationManager$Stub
-android.location.ILocationManager$Stub$Proxy
-android.location.Location
-android.location.Location$1
-android.location.LocationManager
-android.location.LocationRequest
-android.location.LocationRequest$1
-android.media.AmrInputStream
-android.media.AudioFormat
+android.inputmethodservice.InputMethodService
+android.inputmethodservice.SoftInputWindow
 android.media.AudioManager
-android.media.AudioManager$1
-android.media.AudioManager$FocusEventHandlerDelegate
-android.media.AudioManager$FocusEventHandlerDelegate$1
-android.media.AudioManager$OnAudioFocusChangeListener
 android.media.AudioRecord
 android.media.AudioSystem
 android.media.AudioTrack
-android.media.CamcorderProfile
-android.media.CameraProfile
-android.media.DecoderCapabilities
-android.media.EncoderCapabilities
-android.media.ExifInterface
-android.media.IAudioFocusDispatcher
-android.media.IAudioFocusDispatcher$Stub
-android.media.IAudioService
-android.media.IAudioService$Stub
-android.media.IAudioService$Stub$Proxy
 android.media.JetPlayer
-android.media.MediaCodec
-android.media.MediaCodecList
-android.media.MediaCrypto
-android.media.MediaDrm
-android.media.MediaExtractor
-android.media.MediaMetadataRetriever
-android.media.MediaMuxer
-android.media.MediaPlayer
-android.media.MediaPlayer$OnBufferingUpdateListener
-android.media.MediaPlayer$OnCompletionListener
-android.media.MediaPlayer$OnErrorListener
-android.media.MediaPlayer$OnInfoListener
-android.media.MediaPlayer$OnPreparedListener
-android.media.MediaPlayer$OnSeekCompleteListener
 android.media.MediaRecorder
-android.media.MediaScanner
 android.media.RemoteDisplay
-android.media.ResampleInputStream
-android.media.SoundPool
 android.media.ToneGenerator
-android.media.videoeditor.MediaArtistNativeHelper
-android.media.videoeditor.VideoEditorProfile
 android.mtp.MtpDatabase
 android.mtp.MtpDevice
-android.mtp.MtpDeviceInfo
-android.mtp.MtpObjectInfo
-android.mtp.MtpPropertyGroup
-android.mtp.MtpPropertyList
-android.mtp.MtpServer
-android.mtp.MtpStorage
-android.mtp.MtpStorageInfo
-android.net.ConnectivityManager
 android.net.Credentials
 android.net.DhcpResults
 android.net.DhcpResults$1
 android.net.IConnectivityManager
 android.net.IConnectivityManager$Stub
 android.net.IConnectivityManager$Stub$Proxy
+android.net.LinkProperties
+android.net.LinkQualityInfo
 android.net.LocalServerSocket
 android.net.LocalSocket
 android.net.LocalSocketImpl
 android.net.LocalSocketImpl$SocketInputStream
 android.net.LocalSocketImpl$SocketOutputStream
 android.net.NetworkInfo
-android.net.NetworkInfo$1
-android.net.NetworkInfo$DetailedState
-android.net.NetworkInfo$State
+android.net.NetworkQuotaInfo
+android.net.NetworkState
 android.net.NetworkStats
 android.net.NetworkStats$1
+android.net.NetworkStats$Entry
+android.net.NetworkStats$NonMonotonicObserver
 android.net.NetworkUtils
 android.net.Proxy
-android.net.SSLCertificateSocketFactory
-android.net.SSLCertificateSocketFactory$1
-android.net.SSLSessionCache
+android.net.ProxyProperties
 android.net.TrafficStats
 android.net.Uri
 android.net.Uri$1
 android.net.Uri$AbstractHierarchicalUri
 android.net.Uri$AbstractPart
-android.net.Uri$Builder
 android.net.Uri$HierarchicalUri
-android.net.Uri$OpaqueUri
 android.net.Uri$Part
 android.net.Uri$Part$EmptyPart
 android.net.Uri$PathPart
-android.net.Uri$PathSegments
-android.net.Uri$PathSegmentsBuilder
 android.net.Uri$StringUri
-android.net.WebAddress
-android.net.http.AndroidHttpClient
-android.net.http.AndroidHttpClient$1
-android.net.http.AndroidHttpClient$2
-android.net.http.AndroidHttpClient$CurlLogger
-android.net.http.CertificateChainValidator
-android.net.wifi.IWifiManager
-android.net.wifi.IWifiManager$Stub
-android.net.wifi.IWifiManager$Stub$Proxy
-android.net.wifi.WifiManager
-android.net.wifi.WifiManager$ServiceHandler
+android.net.wifi.WifiInfo
 android.net.wifi.WifiNative
-android.nfc.IAppCallback
-android.nfc.IAppCallback$Stub
-android.nfc.INfcAdapter
-android.nfc.INfcAdapter$Stub
-android.nfc.INfcAdapter$Stub$Proxy
-android.nfc.INfcTag
-android.nfc.INfcTag$Stub
-android.nfc.INfcTag$Stub$Proxy
-android.nfc.NfcActivityManager
-android.nfc.NfcAdapter
-android.nfc.NfcAdapter$1
-android.nfc.NfcEvent
-android.nfc.NfcManager
 android.opengl.EGL14
+android.opengl.EGLConfig
+android.opengl.EGLContext
+android.opengl.EGLDisplay
+android.opengl.EGLExt
+android.opengl.EGLObjectHandle
+android.opengl.EGLSurface
 android.opengl.ETC1
 android.opengl.GLES10
 android.opengl.GLES10Ext
 android.opengl.GLES11
 android.opengl.GLES11Ext
 android.opengl.GLES20
+android.opengl.GLES30
 android.opengl.GLUtils
 android.opengl.ManagedEGLContext
 android.opengl.Matrix
 android.opengl.Visibility
 android.os.AsyncTask$1
-android.os.AsyncTask$2
-android.os.AsyncTask$3
-android.os.AsyncTask$AsyncTaskResult
 android.os.AsyncTask$InternalHandler
 android.os.AsyncTask$SerialExecutor
-android.os.AsyncTask$SerialExecutor$1
-android.os.AsyncTask$Status
-android.os.AsyncTask$WorkerRunnable
 android.os.Binder
+android.os.Binder$1
 android.os.BinderProxy
 android.os.Build
 android.os.Build$VERSION
 android.os.Bundle
 android.os.Bundle$1
-android.os.CancellationSignal
 android.os.CancellationSignal$OnCancelListener
 android.os.Debug
 android.os.Debug$MemoryInfo
 android.os.Debug$MemoryInfo$1
 android.os.DropBoxManager
+android.os.DropBoxManager$Entry
 android.os.Environment
 android.os.Environment$UserEnvironment
 android.os.FileObserver$ObserverThread
 android.os.FileUtils
 android.os.Handler
-android.os.Handler$Callback
-android.os.Handler$MessengerImpl
 android.os.HandlerThread
 android.os.IBinder
 android.os.IBinder$DeathRecipient
-android.os.ICancellationSignal
-android.os.ICancellationSignal$Stub
 android.os.IInterface
-android.os.IMessenger
-android.os.IMessenger$Stub
-android.os.IMessenger$Stub$Proxy
-android.os.IPowerManager
-android.os.IPowerManager$Stub
-android.os.IPowerManager$Stub$Proxy
 android.os.IServiceManager
 android.os.Looper
 android.os.MemoryFile
@@ -733,27 +483,21 @@
 android.os.MessageQueue
 android.os.MessageQueue$IdleHandler
 android.os.Messenger
-android.os.Messenger$1
+android.os.NetworkOnMainThreadException
 android.os.Parcel
 android.os.Parcel$1
 android.os.ParcelFileDescriptor
 android.os.ParcelFileDescriptor$1
-android.os.ParcelFileDescriptor$AutoCloseInputStream
 android.os.Parcelable
-android.os.Parcelable$ClassLoaderCreator
 android.os.Parcelable$Creator
 android.os.PatternMatcher
 android.os.PatternMatcher$1
-android.os.PowerManager
-android.os.PowerManager$WakeLock
-android.os.PowerManager$WakeLock$1
 android.os.Process
 android.os.RemoteException
 android.os.SELinux
 android.os.ServiceManager
 android.os.ServiceManagerNative
 android.os.ServiceManagerProxy
-android.os.StatFs
 android.os.StrictMode
 android.os.StrictMode$1
 android.os.StrictMode$2
@@ -763,6 +507,7 @@
 android.os.StrictMode$6
 android.os.StrictMode$7
 android.os.StrictMode$8
+android.os.StrictMode$9
 android.os.StrictMode$AndroidBlockGuardPolicy
 android.os.StrictMode$AndroidBlockGuardPolicy$1
 android.os.StrictMode$AndroidCloseGuardReporter
@@ -770,10 +515,13 @@
 android.os.StrictMode$InstanceTracker
 android.os.StrictMode$LogStackTrace
 android.os.StrictMode$Span
+android.os.StrictMode$StrictModeCustomViolation
 android.os.StrictMode$StrictModeDiskReadViolation
 android.os.StrictMode$StrictModeDiskWriteViolation
+android.os.StrictMode$StrictModeNetworkViolation
 android.os.StrictMode$StrictModeViolation
 android.os.StrictMode$ThreadPolicy
+android.os.StrictMode$ThreadPolicy$Builder
 android.os.StrictMode$ThreadSpanState
 android.os.StrictMode$ViolationInfo
 android.os.StrictMode$VmPolicy
@@ -787,146 +535,58 @@
 android.os.UserHandle$1
 android.os.storage.IMountService
 android.os.storage.IMountService$Stub
-android.os.storage.IMountService$Stub$Proxy
-android.os.storage.StorageManager
-android.os.storage.StorageVolume
-android.os.storage.StorageVolume$1
-android.preference.CheckBoxPreference
-android.preference.GenericInflater
-android.preference.GenericInflater$Parent
-android.preference.Preference
-android.preference.Preference$OnPreferenceChangeInternalListener
-android.preference.Preference$OnPreferenceChangeListener
-android.preference.PreferenceActivity
-android.preference.PreferenceActivity$1
-android.preference.PreferenceFragment
-android.preference.PreferenceFragment$OnPreferenceStartFragmentCallback
-android.preference.PreferenceFrameLayout
-android.preference.PreferenceGroup
-android.preference.PreferenceGroupAdapter
-android.preference.PreferenceGroupAdapter$1
-android.preference.PreferenceGroupAdapter$PreferenceLayout
-android.preference.PreferenceInflater
-android.preference.PreferenceManager
-android.preference.PreferenceManager$OnPreferenceTreeClickListener
-android.preference.PreferenceScreen
-android.preference.TwoStatePreference
-android.provider.BaseColumns
-android.provider.ContactsContract
 android.provider.Settings$Global
-android.provider.Settings$NameValueCache
-android.provider.Settings$NameValueTable
 android.provider.Settings$Secure
-android.provider.Settings$SettingNotFoundException
 android.provider.Settings$System
 android.renderscript.RenderScript
 android.security.AndroidKeyPairGenerator
 android.security.AndroidKeyStore
 android.security.AndroidKeyStoreProvider
-android.telephony.Rlog
+android.service.dreams.DreamService
 android.telephony.TelephonyManager
 android.text.AndroidBidi
 android.text.AndroidCharacter
 android.text.BoringLayout
-android.text.BoringLayout$Metrics
-android.text.DynamicLayout
-android.text.DynamicLayout$ChangeWatcher
 android.text.Editable
-android.text.Editable$Factory
 android.text.GetChars
 android.text.GraphicsOperations
-android.text.Html
-android.text.Html$HtmlParser
-android.text.HtmlToSpannedConverter
-android.text.InputFilter
 android.text.InputType
 android.text.Layout
-android.text.Layout$1
-android.text.Layout$Alignment
-android.text.Layout$Directions
-android.text.Layout$Ellipsizer
 android.text.MeasuredText
 android.text.NoCopySpan
-android.text.NoCopySpan$Concrete
-android.text.PackedIntVector
-android.text.PackedObjectVector
 android.text.ParcelableSpan
 android.text.Selection
-android.text.Selection$END
-android.text.Selection$START
-android.text.SpanSet
 android.text.SpanWatcher
 android.text.Spannable
-android.text.Spannable$Factory
 android.text.SpannableString
 android.text.SpannableStringBuilder
 android.text.SpannableStringInternal
 android.text.Spanned
 android.text.SpannedString
-android.text.StaticLayout
 android.text.TextDirectionHeuristic
 android.text.TextDirectionHeuristics
-android.text.TextDirectionHeuristics$AnyStrong
-android.text.TextDirectionHeuristics$FirstStrong
-android.text.TextDirectionHeuristics$TextDirectionAlgorithm
-android.text.TextDirectionHeuristics$TextDirectionHeuristicImpl
-android.text.TextDirectionHeuristics$TextDirectionHeuristicInternal
-android.text.TextDirectionHeuristics$TextDirectionHeuristicLocale
-android.text.TextLine
 android.text.TextPaint
 android.text.TextUtils
 android.text.TextUtils$1
 android.text.TextUtils$EllipsizeCallback
+android.text.TextUtils$Reverser
 android.text.TextUtils$TruncateAt
-android.text.TextWatcher
-android.text.format.DateFormat
-android.text.format.DateUtils
 android.text.format.Time
-android.text.method.AllCapsTransformationMethod
-android.text.method.ArrowKeyMovementMethod
 android.text.method.BaseKeyListener
-android.text.method.BaseMovementMethod
 android.text.method.KeyListener
-android.text.method.LinkMovementMethod
 android.text.method.MetaKeyKeyListener
-android.text.method.MovementMethod
-android.text.method.PasswordTransformationMethod
-android.text.method.ReplacementTransformationMethod
-android.text.method.ReplacementTransformationMethod$ReplacementCharSequence
-android.text.method.ReplacementTransformationMethod$SpannedReplacementCharSequence
-android.text.method.ScrollingMovementMethod
-android.text.method.SingleLineTransformationMethod
 android.text.method.TextKeyListener
-android.text.method.TextKeyListener$Capitalize
-android.text.method.TransformationMethod
-android.text.method.TransformationMethod2
-android.text.style.AlignmentSpan
 android.text.style.CharacterStyle
-android.text.style.ClickableSpan
-android.text.style.DynamicDrawableSpan
-android.text.style.EasyEditSpan
-android.text.style.ImageSpan
-android.text.style.LeadingMarginSpan
-android.text.style.LineBackgroundSpan
-android.text.style.LineHeightSpan
 android.text.style.MetricAffectingSpan
-android.text.style.ParagraphStyle
 android.text.style.ReplacementSpan
-android.text.style.SpellCheckSpan
-android.text.style.StyleSpan
-android.text.style.SuggestionSpan
-android.text.style.URLSpan
-android.text.style.UnderlineSpan
 android.text.style.UpdateAppearance
 android.text.style.UpdateLayout
-android.text.style.WrapTogetherSpan
 android.util.AndroidException
 android.util.AndroidRuntimeException
+android.util.ArrayMap
+android.util.ArraySet
 android.util.AttributeSet
-android.util.Base64
-android.util.Base64$Coder
-android.util.Base64$Decoder
-android.util.Base64$Encoder
+android.util.ContainerHelpers
 android.util.DisplayMetrics
 android.util.EventLog
 android.util.EventLog$Event
@@ -934,15 +594,13 @@
 android.util.FloatProperty
 android.util.Log
 android.util.Log$1
+android.util.Log$TerribleFailure
 android.util.Log$TerribleFailureHandler
 android.util.LongSparseArray
-android.util.LruCache
-android.util.Pair
-android.util.Patterns
+android.util.LongSparseLongArray
 android.util.Pools$Pool
 android.util.Pools$SimplePool
 android.util.Pools$SynchronizedPool
-android.util.PrefixPrinter
 android.util.PrintWriterPrinter
 android.util.Printer
 android.util.Property
@@ -952,48 +610,39 @@
 android.util.SparseBooleanArray
 android.util.SparseIntArray
 android.util.StateSet
+android.util.SuperNotCalledException
 android.util.TypedValue
 android.util.Xml
 android.view.AbsSavedState
-android.view.AbsSavedState$1
-android.view.AbsSavedState$2
+android.view.AccessibilityInteractionController
+android.view.AccessibilityIterators$AbstractTextSegmentIterator
+android.view.AccessibilityIterators$CharacterTextSegmentIterator
+android.view.AccessibilityIterators$ParagraphTextSegmentIterator
+android.view.AccessibilityIterators$TextSegmentIterator
+android.view.AccessibilityIterators$WordTextSegmentIterator
 android.view.ActionMode
 android.view.ActionMode$Callback
-android.view.ActionProvider$SubUiVisibilityListener
 android.view.Choreographer
-android.view.Choreographer$1
-android.view.Choreographer$2
-android.view.Choreographer$CallbackQueue
-android.view.Choreographer$CallbackRecord
-android.view.Choreographer$FrameDisplayEventReceiver
-android.view.Choreographer$FrameHandler
-android.view.CollapsibleActionView
+android.view.Choreographer$FrameCallback
 android.view.ContextMenu
 android.view.ContextMenu$ContextMenuInfo
 android.view.ContextThemeWrapper
 android.view.Display
+android.view.DisplayAdjustments
 android.view.DisplayEventReceiver
 android.view.DisplayInfo
 android.view.DisplayInfo$1
 android.view.DisplayList
+android.view.DragEvent
 android.view.FallbackEventHandler
 android.view.FocusFinder
-android.view.FocusFinder$1
-android.view.FocusFinder$SequentialFocusComparator
 android.view.GLES20Canvas
-android.view.GLES20Canvas$CanvasFinalizer
 android.view.GLES20DisplayList
-android.view.GLES20DisplayList$DisplayListFinalizer
 android.view.GLES20Layer
-android.view.GLES20Layer$Finalizer
-android.view.GLES20RecordingCanvas
 android.view.GLES20RenderLayer
-android.view.GestureDetector
-android.view.GestureDetector$GestureHandler
-android.view.GestureDetector$OnDoubleTapListener
-android.view.GestureDetector$OnGestureListener
-android.view.GestureDetector$SimpleOnGestureListener
-android.view.Gravity
+android.view.GLES20TextureLayer
+android.view.GraphicBuffer
+android.view.GraphicBuffer$1
 android.view.HardwareCanvas
 android.view.HardwareLayer
 android.view.HardwareRenderer
@@ -1002,18 +651,18 @@
 android.view.HardwareRenderer$Gl20Renderer$2
 android.view.HardwareRenderer$Gl20Renderer$Gl20RendererEglContext
 android.view.HardwareRenderer$GlRenderer
+android.view.HardwareRenderer$GlRenderer$DrawPerformanceDataProvider
 android.view.HardwareRenderer$GlRenderer$FunctorsRunnable
+android.view.HardwareRenderer$GraphDataProvider
 android.view.HardwareRenderer$HardwareDrawCallbacks
-android.view.IRotationWatcher
-android.view.IRotationWatcher$Stub
+android.view.IAssetAtlas
+android.view.IAssetAtlas$Stub
 android.view.IWindow
 android.view.IWindow$Stub
+android.view.IWindowId
 android.view.IWindowManager
 android.view.IWindowManager$Stub
-android.view.IWindowManager$Stub$Proxy
 android.view.IWindowSession
-android.view.IWindowSession$Stub
-android.view.IWindowSession$Stub$Proxy
 android.view.InputChannel
 android.view.InputChannel$1
 android.view.InputDevice
@@ -1036,22 +685,19 @@
 android.view.LayoutInflater
 android.view.LayoutInflater$Factory
 android.view.LayoutInflater$Factory2
-android.view.LayoutInflater$Filter
 android.view.Menu
 android.view.MenuInflater
-android.view.MenuInflater$MenuState
 android.view.MenuItem
-android.view.MenuItem$OnMenuItemClickListener
 android.view.MotionEvent
 android.view.MotionEvent$1
 android.view.MotionEvent$PointerCoords
 android.view.MotionEvent$PointerProperties
 android.view.PointerIcon
 android.view.PointerIcon$1
-android.view.SubMenu
+android.view.SoundEffectConstants
 android.view.Surface
 android.view.Surface$1
-android.view.Surface$CompatibleCanvas
+android.view.Surface$OutOfResourcesException
 android.view.SurfaceControl
 android.view.SurfaceControl$PhysicalDisplayInfo
 android.view.SurfaceHolder
@@ -1059,12 +705,8 @@
 android.view.SurfaceHolder$Callback2
 android.view.SurfaceSession
 android.view.SurfaceView
-android.view.SurfaceView$1
-android.view.SurfaceView$2
-android.view.SurfaceView$3
-android.view.SurfaceView$4
-android.view.SurfaceView$MyWindow
 android.view.TextureView
+android.view.TouchDelegate
 android.view.VelocityTracker
 android.view.VelocityTracker$Estimator
 android.view.View
@@ -1072,6 +714,7 @@
 android.view.View$10
 android.view.View$11
 android.view.View$12
+android.view.View$2
 android.view.View$3
 android.view.View$4
 android.view.View$5
@@ -1082,40 +725,52 @@
 android.view.View$AccessibilityDelegate
 android.view.View$AttachInfo
 android.view.View$AttachInfo$Callbacks
+android.view.View$AttachInfo$InvalidateInfo
 android.view.View$BaseSavedState
-android.view.View$BaseSavedState$1
 android.view.View$CheckForLongPress
 android.view.View$CheckForTap
+android.view.View$DragShadowBuilder
 android.view.View$ListenerInfo
+android.view.View$MatchIdPredicate
+android.view.View$MatchLabelForPredicate
 android.view.View$MeasureSpec
+android.view.View$OnApplyWindowInsetsListener
 android.view.View$OnAttachStateChangeListener
 android.view.View$OnClickListener
 android.view.View$OnCreateContextMenuListener
+android.view.View$OnDragListener
 android.view.View$OnFocusChangeListener
+android.view.View$OnGenericMotionListener
+android.view.View$OnHoverListener
 android.view.View$OnKeyListener
 android.view.View$OnLayoutChangeListener
 android.view.View$OnLongClickListener
+android.view.View$OnSystemUiVisibilityChangeListener
 android.view.View$OnTouchListener
 android.view.View$PerformClick
 android.view.View$ScrollabilityCache
+android.view.View$SendViewScrolledAccessibilityEvent
+android.view.View$SendViewStateChangedAccessibilityEvent
 android.view.View$TransformationInfo
 android.view.View$UnsetPressedState
 android.view.ViewConfiguration
 android.view.ViewDebug
-android.view.ViewDebug$HierarchyHandler
 android.view.ViewGroup
-android.view.ViewGroup$3
 android.view.ViewGroup$LayoutParams
-android.view.ViewGroup$MarginLayoutParams
-android.view.ViewGroup$OnHierarchyChangeListener
-android.view.ViewGroup$TouchTarget
 android.view.ViewManager
+android.view.ViewOverlay
 android.view.ViewParent
+android.view.ViewPropertyAnimator
 android.view.ViewRootImpl
+android.view.ViewRootImpl$1
+android.view.ViewRootImpl$2
 android.view.ViewRootImpl$3
 android.view.ViewRootImpl$4
+android.view.ViewRootImpl$5
+android.view.ViewRootImpl$6
 android.view.ViewRootImpl$AccessibilityInteractionConnectionManager
 android.view.ViewRootImpl$AsyncInputStage
+android.view.ViewRootImpl$CalledFromWrongThreadException
 android.view.ViewRootImpl$ConsumeBatchedInputRunnable
 android.view.ViewRootImpl$EarlyPostImeInputStage
 android.view.ViewRootImpl$ImeInputStage
@@ -1125,13 +780,10 @@
 android.view.ViewRootImpl$NativePreImeInputStage
 android.view.ViewRootImpl$QueuedInputEvent
 android.view.ViewRootImpl$RunQueue
-android.view.ViewRootImpl$RunQueue$HandlerAction
+android.view.ViewRootImpl$SendWindowContentChangedAccessibilityEvent
 android.view.ViewRootImpl$SyntheticInputStage
-android.view.ViewRootImpl$SyntheticJoystickHandler
-android.view.ViewRootImpl$SyntheticTouchNavigationHandler
-android.view.ViewRootImpl$SyntheticTouchNavigationHandler$1
-android.view.ViewRootImpl$SyntheticTrackballHandler
-android.view.ViewRootImpl$TrackballAxis
+android.view.ViewRootImpl$SystemUiVisibilityInfo
+android.view.ViewRootImpl$TakenSurfaceHolder
 android.view.ViewRootImpl$TraversalRunnable
 android.view.ViewRootImpl$ViewPostImeInputStage
 android.view.ViewRootImpl$ViewPreImeInputStage
@@ -1140,245 +792,61 @@
 android.view.ViewRootImpl$WindowInputEventReceiver
 android.view.ViewStub
 android.view.ViewTreeObserver
-android.view.ViewTreeObserver$CopyOnWriteArray
-android.view.ViewTreeObserver$CopyOnWriteArray$Access
 android.view.ViewTreeObserver$InternalInsetsInfo
-android.view.ViewTreeObserver$OnGlobalFocusChangeListener
 android.view.ViewTreeObserver$OnGlobalLayoutListener
-android.view.ViewTreeObserver$OnPreDrawListener
-android.view.ViewTreeObserver$OnScrollChangedListener
-android.view.ViewTreeObserver$OnTouchModeChangeListener
 android.view.Window
 android.view.Window$Callback
+android.view.WindowId
+android.view.WindowInsets
 android.view.WindowLeaked
 android.view.WindowManager
+android.view.WindowManager$BadTokenException
+android.view.WindowManager$InvalidDisplayException
 android.view.WindowManager$LayoutParams
-android.view.WindowManager$LayoutParams$1
 android.view.WindowManagerGlobal
 android.view.WindowManagerGlobal$1
-android.view.WindowManagerImpl
 android.view.accessibility.AccessibilityEvent
 android.view.accessibility.AccessibilityEventSource
 android.view.accessibility.AccessibilityManager
-android.view.accessibility.AccessibilityManager$1
 android.view.accessibility.AccessibilityManager$AccessibilityStateChangeListener
-android.view.accessibility.AccessibilityManager$MyHandler
 android.view.accessibility.AccessibilityNodeInfo
 android.view.accessibility.AccessibilityNodeProvider
 android.view.accessibility.AccessibilityRecord
-android.view.accessibility.IAccessibilityManager
-android.view.accessibility.IAccessibilityManager$Stub
-android.view.accessibility.IAccessibilityManager$Stub$Proxy
-android.view.accessibility.IAccessibilityManagerClient
-android.view.accessibility.IAccessibilityManagerClient$Stub
 android.view.animation.AccelerateDecelerateInterpolator
-android.view.animation.AccelerateInterpolator
-android.view.animation.AlphaAnimation
 android.view.animation.Animation
-android.view.animation.Animation$1
-android.view.animation.Animation$2
-android.view.animation.Animation$3
-android.view.animation.Animation$AnimationListener
-android.view.animation.AnimationSet
 android.view.animation.AnimationUtils
-android.view.animation.DecelerateInterpolator
 android.view.animation.Interpolator
-android.view.animation.LinearInterpolator
+android.view.animation.RotateAnimation
 android.view.animation.Transformation
-android.view.inputmethod.BaseInputConnection
-android.view.inputmethod.ComposingText
 android.view.inputmethod.EditorInfo
-android.view.inputmethod.EditorInfo$1
-android.view.inputmethod.ExtractedText
-android.view.inputmethod.ExtractedText$1
 android.view.inputmethod.InputConnection
 android.view.inputmethod.InputMethodManager
-android.view.inputmethod.InputMethodManager$1
-android.view.inputmethod.InputMethodManager$ControlledInputConnectionWrapper
 android.view.inputmethod.InputMethodManager$FinishedInputEventCallback
-android.view.inputmethod.InputMethodManager$H
-android.view.inputmethod.InputMethodManager$ImeInputEventSender
-android.view.inputmethod.InputMethodManager$PendingEvent
-android.view.textservice.SpellCheckerSubtype
-android.view.textservice.SpellCheckerSubtype$1
-android.webkit.CookieManager
-android.webkit.CookieSyncManager
-android.webkit.GeolocationPermissions
-android.webkit.JavascriptInterface
-android.webkit.URLUtil
-android.webkit.WebBackForwardList
-android.webkit.WebHistoryItem
-android.webkit.WebIconDatabase
-android.webkit.WebSettings
-android.webkit.WebSettings$LayoutAlgorithm
-android.webkit.WebSettings$PluginState
-android.webkit.WebSettings$RenderPriority
-android.webkit.WebSettings$ZoomDensity
-android.webkit.WebStorage
-android.webkit.WebSyncManager
-android.webkit.WebSyncManager$SyncHandler
-android.webkit.WebView
-android.webkit.WebView$PrivateAccess
-android.webkit.WebViewClient
-android.webkit.WebViewDatabase
-android.webkit.WebViewFactory
-android.webkit.WebViewFactory$Preloader
-android.webkit.WebViewFactoryProvider
-android.webkit.WebViewFactoryProvider$Statics
-android.webkit.WebViewProvider
-android.webkit.WebViewProvider$ScrollDelegate
-android.webkit.WebViewProvider$ViewDelegate
-android.widget.AbsListView
-android.widget.AbsListView$1
-android.widget.AbsListView$AdapterDataSetObserver
-android.widget.AbsListView$CheckForTap
-android.widget.AbsListView$LayoutParams
-android.widget.AbsListView$OnScrollListener
-android.widget.AbsListView$PerformClick
-android.widget.AbsListView$RecycleBin
-android.widget.AbsListView$SavedState
-android.widget.AbsListView$SavedState$1
-android.widget.AbsListView$SelectionBoundsAdjuster
-android.widget.AbsListView$WindowRunnnable
-android.widget.AbsSeekBar
-android.widget.AbsSpinner
-android.widget.AbsSpinner$RecycleBin
-android.widget.AbsoluteLayout
-android.widget.Adapter
-android.widget.AdapterView
-android.widget.AdapterView$AdapterDataSetObserver
-android.widget.AdapterView$OnItemClickListener
-android.widget.AdapterView$OnItemLongClickListener
-android.widget.AdapterView$OnItemSelectedListener
-android.widget.AdapterView$SelectionNotifier
-android.widget.AdapterViewAnimator
-android.widget.ArrayAdapter
-android.widget.AutoCompleteTextView
-android.widget.AutoCompleteTextView$DropDownItemClickListener
-android.widget.AutoCompleteTextView$MyWatcher
-android.widget.AutoCompleteTextView$PassThroughClickListener
-android.widget.BaseAdapter
-android.widget.Button
-android.widget.CheckBox
-android.widget.Checkable
-android.widget.CompoundButton
-android.widget.CompoundButton$OnCheckedChangeListener
-android.widget.CursorAdapter
-android.widget.CursorAdapter$ChangeObserver
-android.widget.CursorAdapter$MyDataSetObserver
-android.widget.CursorFilter$CursorFilterClient
-android.widget.EdgeEffect
 android.widget.EditText
-android.widget.Editor
-android.widget.Editor$Blink
-android.widget.Editor$InputContentType
-android.widget.Editor$InputMethodState
-android.widget.ExpandableListView
-android.widget.Filter
-android.widget.Filter$FilterListener
-android.widget.Filterable
 android.widget.FrameLayout
-android.widget.FrameLayout$LayoutParams
 android.widget.GridLayout
-android.widget.GridView
-android.widget.ImageButton
 android.widget.ImageView
-android.widget.ImageView$ScaleType
 android.widget.LinearLayout
 android.widget.LinearLayout$LayoutParams
-android.widget.ListAdapter
-android.widget.ListPopupWindow
-android.widget.ListPopupWindow$1
-android.widget.ListPopupWindow$2
-android.widget.ListPopupWindow$DropDownListView
-android.widget.ListPopupWindow$ListSelectorHider
-android.widget.ListPopupWindow$PopupDataSetObserver
-android.widget.ListPopupWindow$PopupScrollListener
-android.widget.ListPopupWindow$PopupTouchInterceptor
-android.widget.ListPopupWindow$ResizePopupRunnable
-android.widget.ListView
-android.widget.ListView$ArrowScrollFocusResult
-android.widget.OverScroller
 android.widget.OverScroller$SplineOverScroller
-android.widget.PopupWindow
-android.widget.PopupWindow$1
-android.widget.PopupWindow$OnDismissListener
-android.widget.PopupWindow$PopupViewContainer
-android.widget.ProgressBar
-android.widget.ProgressBar$SavedState
-android.widget.ProgressBar$SavedState$1
 android.widget.RelativeLayout
-android.widget.RelativeLayout$DependencyGraph
-android.widget.RelativeLayout$DependencyGraph$Node
-android.widget.RelativeLayout$LayoutParams
-android.widget.RemoteViews
-android.widget.RemoteViews$1
-android.widget.RemoteViews$Action
-android.widget.RemoteViews$BitmapCache
-android.widget.RemoteViews$MemoryUsageCounter
-android.widget.RemoteViews$OnClickHandler
-android.widget.RemoteViews$ReflectionAction
-android.widget.RemoteViewsAdapter$RemoteAdapterConnectionCallback
 android.widget.ScrollBarDrawable
 android.widget.ScrollView
 android.widget.Scroller
-android.widget.SearchView
-android.widget.SearchView$1
-android.widget.SearchView$10
-android.widget.SearchView$11
-android.widget.SearchView$2
-android.widget.SearchView$3
-android.widget.SearchView$4
-android.widget.SearchView$5
-android.widget.SearchView$6
-android.widget.SearchView$7
-android.widget.SearchView$8
-android.widget.SearchView$9
-android.widget.SearchView$SearchAutoComplete
-android.widget.Spinner
-android.widget.Spinner$DropDownAdapter
-android.widget.Spinner$DropdownPopup
-android.widget.Spinner$DropdownPopup$1
-android.widget.Spinner$SpinnerPopup
-android.widget.SpinnerAdapter
-android.widget.TableLayout
-android.widget.TableLayout$LayoutParams
-android.widget.TableLayout$PassThroughHierarchyChangeListener
-android.widget.TableRow
-android.widget.TableRow$ChildrenTracker
-android.widget.TableRow$LayoutParams
+android.widget.TextClock
 android.widget.TextView
-android.widget.TextView$2
-android.widget.TextView$4
-android.widget.TextView$BufferType
-android.widget.TextView$ChangeWatcher
-android.widget.TextView$CharWrapper
-android.widget.TextView$Drawables
-android.widget.TextView$OnEditorActionListener
-android.widget.TextView$SavedState
-android.widget.TextView$SavedState$1
-android.widget.Toast
-android.widget.Toast$TN
-android.widget.Toast$TN$1
-android.widget.Toast$TN$2
-com.android.i18n.phonenumbers.PhoneNumberMatcher
-com.android.i18n.phonenumbers.PhoneNumberUtil
 com.android.internal.R$styleable
 com.android.internal.app.ActionBarImpl
-com.android.internal.app.ActionBarImpl$1
-com.android.internal.app.ActionBarImpl$2
-com.android.internal.app.AlertController
-com.android.internal.app.AlertController$1
-com.android.internal.app.AlertController$AlertParams
-com.android.internal.app.AlertController$ButtonHandler
-com.android.internal.appwidget.IAppWidgetService
-com.android.internal.appwidget.IAppWidgetService$Stub
-com.android.internal.appwidget.IAppWidgetService$Stub$Proxy
+com.android.internal.app.IAppOpsService
+com.android.internal.app.IAppOpsService$Stub
 com.android.internal.content.NativeLibraryHelper
 com.android.internal.logging.AndroidConfig
 com.android.internal.logging.AndroidHandler
 com.android.internal.logging.AndroidHandler$1
+com.android.internal.net.LegacyVpnInfo
 com.android.internal.net.NetworkStatsFactory
+com.android.internal.net.VpnConfig
+com.android.internal.net.VpnProfile
 com.android.internal.os.AndroidPrintStream
 com.android.internal.os.BinderInternal
 com.android.internal.os.BinderInternal$GcWatcher
@@ -1397,162 +865,40 @@
 com.android.internal.os.ZygoteConnection$Arguments
 com.android.internal.os.ZygoteInit
 com.android.internal.os.ZygoteInit$MethodAndArgsCaller
-com.android.internal.policy.IPolicy
 com.android.internal.policy.PolicyManager
-com.android.internal.policy.impl.PhoneFallbackEventHandler
 com.android.internal.policy.impl.PhoneLayoutInflater
 com.android.internal.policy.impl.PhoneWindow
-com.android.internal.policy.impl.PhoneWindow$1
-com.android.internal.policy.impl.PhoneWindow$2
-com.android.internal.policy.impl.PhoneWindow$ActionMenuPresenterCallback
 com.android.internal.policy.impl.PhoneWindow$DecorView
-com.android.internal.policy.impl.PhoneWindow$DialogMenuCallback
-com.android.internal.policy.impl.PhoneWindow$PanelFeatureState
-com.android.internal.policy.impl.PhoneWindow$PanelFeatureState$SavedState
-com.android.internal.policy.impl.PhoneWindow$PanelFeatureState$SavedState$1
-com.android.internal.policy.impl.PhoneWindow$RotationWatcher
-com.android.internal.policy.impl.PhoneWindow$RotationWatcher$1
 com.android.internal.policy.impl.Policy
-com.android.internal.telephony.ITelephony
-com.android.internal.telephony.ITelephony$Stub
-com.android.internal.telephony.ITelephony$Stub$Proxy
-com.android.internal.telephony.ITelephonyRegistry
-com.android.internal.telephony.ITelephonyRegistry$Stub
-com.android.internal.telephony.ITelephonyRegistry$Stub$Proxy
-com.android.internal.telephony.PhoneConstants$State
-com.android.internal.textservice.ITextServicesManager
-com.android.internal.textservice.ITextServicesManager$Stub
 com.android.internal.util.ArrayUtils
-com.android.internal.util.AsyncChannel
-com.android.internal.util.AsyncChannel$DeathMonitor
-com.android.internal.util.FastXmlSerializer
-com.android.internal.util.MemInfoReader
+com.android.internal.util.FastMath
+com.android.internal.util.FastPrintWriter
 com.android.internal.util.Preconditions
+com.android.internal.util.Predicate
+com.android.internal.util.TypedProperties
 com.android.internal.util.XmlUtils
-com.android.internal.view.ActionBarPolicy
-com.android.internal.view.BaseIWindow
-com.android.internal.view.IInputConnectionWrapper
-com.android.internal.view.IInputConnectionWrapper$MyHandler
-com.android.internal.view.IInputConnectionWrapper$SomeArgs
+com.android.internal.view.BaseSurfaceHolder
 com.android.internal.view.IInputContext
-com.android.internal.view.IInputContext$Stub
-com.android.internal.view.IInputContextCallback
-com.android.internal.view.IInputContextCallback$Stub
-com.android.internal.view.IInputContextCallback$Stub$Proxy
 com.android.internal.view.IInputMethodClient
-com.android.internal.view.IInputMethodClient$Stub
-com.android.internal.view.IInputMethodManager
-com.android.internal.view.IInputMethodManager$Stub
-com.android.internal.view.IInputMethodManager$Stub$Proxy
-com.android.internal.view.IInputMethodSession
-com.android.internal.view.IInputMethodSession$Stub
-com.android.internal.view.IInputMethodSession$Stub$Proxy
-com.android.internal.view.InputBindResult
-com.android.internal.view.InputBindResult$1
 com.android.internal.view.RootViewSurfaceTaker
-com.android.internal.view.menu.ActionMenuItem
-com.android.internal.view.menu.ActionMenuItemView
-com.android.internal.view.menu.ActionMenuPresenter
-com.android.internal.view.menu.ActionMenuPresenter$OverflowMenuButton
-com.android.internal.view.menu.ActionMenuPresenter$PopupPresenterCallback
-com.android.internal.view.menu.ActionMenuPresenter$SavedState
-com.android.internal.view.menu.ActionMenuPresenter$SavedState$1
-com.android.internal.view.menu.ActionMenuView
-com.android.internal.view.menu.ActionMenuView$ActionMenuChildView
-com.android.internal.view.menu.ActionMenuView$LayoutParams
-com.android.internal.view.menu.BaseMenuPresenter
-com.android.internal.view.menu.ListMenuItemView
 com.android.internal.view.menu.MenuBuilder
-com.android.internal.view.menu.MenuBuilder$Callback
-com.android.internal.view.menu.MenuBuilder$ItemInvoker
-com.android.internal.view.menu.MenuItemImpl
-com.android.internal.view.menu.MenuPopupHelper
-com.android.internal.view.menu.MenuPopupHelper$MenuAdapter
-com.android.internal.view.menu.MenuPresenter
-com.android.internal.view.menu.MenuPresenter$Callback
-com.android.internal.view.menu.MenuView
-com.android.internal.view.menu.MenuView$ItemView
-com.android.internal.view.menu.SubMenuBuilder
-com.android.internal.widget.AbsActionBarView
-com.android.internal.widget.AbsActionBarView$VisibilityAnimListener
-com.android.internal.widget.ActionBarContainer
-com.android.internal.widget.ActionBarContextView
-com.android.internal.widget.ActionBarOverlayLayout
-com.android.internal.widget.ActionBarOverlayLayout$LayoutParams
-com.android.internal.widget.ActionBarView
-com.android.internal.widget.ActionBarView$1
-com.android.internal.widget.ActionBarView$2
-com.android.internal.widget.ActionBarView$3
-com.android.internal.widget.ActionBarView$ExpandedActionViewMenuPresenter
-com.android.internal.widget.ActionBarView$HomeView
-com.android.internal.widget.ActionBarView$SavedState
-com.android.internal.widget.ActionBarView$SavedState$1
-com.android.internal.widget.DialogTitle
-com.android.internal.widget.EditableInputConnection
-com.android.org.bouncycastle.asn1.ASN1Boolean
-com.android.org.bouncycastle.asn1.ASN1Choice
+com.android.internal.widget.SwipeDismissLayout
+com.android.okhttp.ConnectionPool
+com.android.okhttp.OkHttpClient
+com.android.okhttp.internal.tls.OkHostnameVerifier
 com.android.org.bouncycastle.asn1.ASN1Encodable
-com.android.org.bouncycastle.asn1.ASN1EncodableVector
-com.android.org.bouncycastle.asn1.ASN1InputStream
-com.android.org.bouncycastle.asn1.ASN1Integer
-com.android.org.bouncycastle.asn1.ASN1Null
 com.android.org.bouncycastle.asn1.ASN1Object
 com.android.org.bouncycastle.asn1.ASN1ObjectIdentifier
-com.android.org.bouncycastle.asn1.ASN1OctetString
-com.android.org.bouncycastle.asn1.ASN1OctetStringParser
 com.android.org.bouncycastle.asn1.ASN1Primitive
-com.android.org.bouncycastle.asn1.ASN1Sequence
-com.android.org.bouncycastle.asn1.ASN1Set
-com.android.org.bouncycastle.asn1.ASN1StreamParser
-com.android.org.bouncycastle.asn1.ASN1String
-com.android.org.bouncycastle.asn1.ASN1TaggedObject
-com.android.org.bouncycastle.asn1.ASN1TaggedObjectParser
-com.android.org.bouncycastle.asn1.BERTags
-com.android.org.bouncycastle.asn1.DERBitString
-com.android.org.bouncycastle.asn1.DERBoolean
-com.android.org.bouncycastle.asn1.DERFactory
-com.android.org.bouncycastle.asn1.DERIA5String
-com.android.org.bouncycastle.asn1.DERInteger
-com.android.org.bouncycastle.asn1.DERNull
 com.android.org.bouncycastle.asn1.DERObjectIdentifier
-com.android.org.bouncycastle.asn1.DEROctetString
-com.android.org.bouncycastle.asn1.DERPrintableString
-com.android.org.bouncycastle.asn1.DERSequence
-com.android.org.bouncycastle.asn1.DERSet
-com.android.org.bouncycastle.asn1.DERT61String
-com.android.org.bouncycastle.asn1.DERTaggedObject
-com.android.org.bouncycastle.asn1.DERUniversalString
-com.android.org.bouncycastle.asn1.DLSequence
-com.android.org.bouncycastle.asn1.DLSet
-com.android.org.bouncycastle.asn1.DefiniteLengthInputStream
-com.android.org.bouncycastle.asn1.InMemoryRepresentable
-com.android.org.bouncycastle.asn1.IndefiniteLengthInputStream
-com.android.org.bouncycastle.asn1.LimitedInputStream
-com.android.org.bouncycastle.asn1.StreamUtil
 com.android.org.bouncycastle.asn1.bc.BCObjectIdentifiers
 com.android.org.bouncycastle.asn1.iana.IANAObjectIdentifiers
 com.android.org.bouncycastle.asn1.nist.NISTObjectIdentifiers
 com.android.org.bouncycastle.asn1.oiw.OIWObjectIdentifiers
 com.android.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers
-com.android.org.bouncycastle.asn1.x509.AlgorithmIdentifier
-com.android.org.bouncycastle.asn1.x509.BasicConstraints
-com.android.org.bouncycastle.asn1.x509.Extension
-com.android.org.bouncycastle.asn1.x509.GeneralName
-com.android.org.bouncycastle.asn1.x509.GeneralNames
-com.android.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo
-com.android.org.bouncycastle.asn1.x509.X509Extension
-com.android.org.bouncycastle.asn1.x509.X509Extensions
 com.android.org.bouncycastle.asn1.x509.X509Name
 com.android.org.bouncycastle.asn1.x509.X509ObjectIdentifiers
-com.android.org.bouncycastle.asn1.x9.X962NamedCurves
 com.android.org.bouncycastle.asn1.x9.X9ObjectIdentifiers
-com.android.org.bouncycastle.crypto.Digest
-com.android.org.bouncycastle.crypto.ExtendedDigest
-com.android.org.bouncycastle.crypto.digests.AndroidDigestFactory
-com.android.org.bouncycastle.crypto.digests.AndroidDigestFactoryInterface
-com.android.org.bouncycastle.crypto.digests.AndroidDigestFactoryOpenSSL
-com.android.org.bouncycastle.crypto.digests.OpenSSLDigest
-com.android.org.bouncycastle.crypto.digests.OpenSSLDigest$SHA1
 com.android.org.bouncycastle.jcajce.provider.asymmetric.DH$Mappings
 com.android.org.bouncycastle.jcajce.provider.asymmetric.DSA$Mappings
 com.android.org.bouncycastle.jcajce.provider.asymmetric.EC$Mappings
@@ -1572,12 +918,16 @@
 com.android.org.bouncycastle.jcajce.provider.digest.MD5$Mappings
 com.android.org.bouncycastle.jcajce.provider.digest.SHA1
 com.android.org.bouncycastle.jcajce.provider.digest.SHA1$Mappings
+com.android.org.bouncycastle.jcajce.provider.digest.SHA224
+com.android.org.bouncycastle.jcajce.provider.digest.SHA224$Mappings
 com.android.org.bouncycastle.jcajce.provider.digest.SHA256
 com.android.org.bouncycastle.jcajce.provider.digest.SHA256$Mappings
 com.android.org.bouncycastle.jcajce.provider.digest.SHA384
 com.android.org.bouncycastle.jcajce.provider.digest.SHA384$Mappings
 com.android.org.bouncycastle.jcajce.provider.digest.SHA512
 com.android.org.bouncycastle.jcajce.provider.digest.SHA512$Mappings
+com.android.org.bouncycastle.jcajce.provider.keystore.BC$Mappings
+com.android.org.bouncycastle.jcajce.provider.keystore.PKCS12$Mappings
 com.android.org.bouncycastle.jcajce.provider.symmetric.AES
 com.android.org.bouncycastle.jcajce.provider.symmetric.AES$Mappings
 com.android.org.bouncycastle.jcajce.provider.symmetric.ARC4
@@ -1588,142 +938,39 @@
 com.android.org.bouncycastle.jcajce.provider.symmetric.DES$Mappings
 com.android.org.bouncycastle.jcajce.provider.symmetric.DESede
 com.android.org.bouncycastle.jcajce.provider.symmetric.DESede$Mappings
+com.android.org.bouncycastle.jcajce.provider.symmetric.PBEPKCS12
+com.android.org.bouncycastle.jcajce.provider.symmetric.PBEPKCS12$Mappings
+com.android.org.bouncycastle.jcajce.provider.symmetric.RC2
+com.android.org.bouncycastle.jcajce.provider.symmetric.RC2$Mappings
+com.android.org.bouncycastle.jcajce.provider.symmetric.SymmetricAlgorithmProvider
+com.android.org.bouncycastle.jcajce.provider.symmetric.Twofish
+com.android.org.bouncycastle.jcajce.provider.symmetric.Twofish$Mappings
 com.android.org.bouncycastle.jcajce.provider.util.AlgorithmProvider
 com.android.org.bouncycastle.jcajce.provider.util.AsymmetricAlgorithmProvider
 com.android.org.bouncycastle.jcajce.provider.util.AsymmetricKeyInfoConverter
-com.android.org.bouncycastle.jce.interfaces.BCKeyStore
 com.android.org.bouncycastle.jce.provider.BouncyCastleProvider
 com.android.org.bouncycastle.jce.provider.BouncyCastleProvider$1
 com.android.org.bouncycastle.jce.provider.BouncyCastleProviderConfiguration
 com.android.org.bouncycastle.jce.provider.CertBlacklist
 com.android.org.bouncycastle.jce.provider.CertPathValidatorUtilities
-com.android.org.bouncycastle.jce.provider.PKIXCRLUtil
 com.android.org.bouncycastle.jce.provider.PKIXCertPathValidatorSpi
-com.android.org.bouncycastle.jce.provider.PKIXNameConstraintValidator
-com.android.org.bouncycastle.jce.provider.PKIXPolicyNode
-com.android.org.bouncycastle.jce.provider.RFC3280CertPathUtilities
-com.android.org.bouncycastle.util.Arrays
 com.android.org.bouncycastle.util.Strings
-com.android.org.bouncycastle.util.encoders.Encoder
-com.android.org.bouncycastle.util.encoders.Hex
-com.android.org.bouncycastle.util.encoders.HexEncoder
-com.android.org.bouncycastle.util.io.Streams
-com.android.org.bouncycastle.x509.ExtendedPKIXParameters
-com.android.org.conscrypt.AbstractSessionContext
-com.android.org.conscrypt.AbstractSessionContext$1
-com.android.org.conscrypt.ByteArray
-com.android.org.conscrypt.CertPinManager
-com.android.org.conscrypt.ChainStrengthAnalyzer
-com.android.org.conscrypt.ClientSessionContext
-com.android.org.conscrypt.ClientSessionContext$HostAndPort
-com.android.org.conscrypt.DefaultSSLContextImpl
-com.android.org.conscrypt.FileClientSessionCache
-com.android.org.conscrypt.FileClientSessionCache$Impl
 com.android.org.conscrypt.JSSEProvider
 com.android.org.conscrypt.KeyManagerFactoryImpl
-com.android.org.conscrypt.KeyManagerImpl
 com.android.org.conscrypt.NativeCrypto
 com.android.org.conscrypt.NativeCrypto$SSLHandshakeCallbacks
-com.android.org.conscrypt.OpenSSLBIOInputStream
-com.android.org.conscrypt.OpenSSLCipher
-com.android.org.conscrypt.OpenSSLCipher$AES
-com.android.org.conscrypt.OpenSSLCipher$AES$CBC
-com.android.org.conscrypt.OpenSSLCipher$AES$CBC$NoPadding
-com.android.org.conscrypt.OpenSSLCipher$AES$CBC$PKCS5Padding
-com.android.org.conscrypt.OpenSSLCipher$AES$CFB
-com.android.org.conscrypt.OpenSSLCipher$AES$CTR
-com.android.org.conscrypt.OpenSSLCipher$AES$ECB
-com.android.org.conscrypt.OpenSSLCipher$AES$ECB$NoPadding
-com.android.org.conscrypt.OpenSSLCipher$AES$ECB$PKCS5Padding
-com.android.org.conscrypt.OpenSSLCipher$AES$OFB
-com.android.org.conscrypt.OpenSSLCipher$ARC4
-com.android.org.conscrypt.OpenSSLCipher$DESEDE
-com.android.org.conscrypt.OpenSSLCipher$DESEDE$CBC
-com.android.org.conscrypt.OpenSSLCipher$DESEDE$CBC$NoPadding
-com.android.org.conscrypt.OpenSSLCipher$DESEDE$CBC$PKCS5Padding
-com.android.org.conscrypt.OpenSSLCipher$DESEDE$CFB
-com.android.org.conscrypt.OpenSSLCipher$DESEDE$ECB
-com.android.org.conscrypt.OpenSSLCipher$DESEDE$ECB$NoPadding
-com.android.org.conscrypt.OpenSSLCipher$DESEDE$ECB$PKCS5Padding
-com.android.org.conscrypt.OpenSSLCipher$DESEDE$OFB
-com.android.org.conscrypt.OpenSSLCipherRSA
-com.android.org.conscrypt.OpenSSLCipherRSA$PKCS1
-com.android.org.conscrypt.OpenSSLCipherRSA$Raw
-com.android.org.conscrypt.OpenSSLContextImpl
-com.android.org.conscrypt.OpenSSLDSAKeyFactory
-com.android.org.conscrypt.OpenSSLDSAKeyPairGenerator
-com.android.org.conscrypt.OpenSSLECDHKeyAgreement
-com.android.org.conscrypt.OpenSSLECKeyFactory
-com.android.org.conscrypt.OpenSSLECKeyPairGenerator
-com.android.org.conscrypt.OpenSSLKey
-com.android.org.conscrypt.OpenSSLKeyHolder
-com.android.org.conscrypt.OpenSSLMac
-com.android.org.conscrypt.OpenSSLMac$HmacMD5
-com.android.org.conscrypt.OpenSSLMac$HmacSHA1
-com.android.org.conscrypt.OpenSSLMac$HmacSHA256
-com.android.org.conscrypt.OpenSSLMac$HmacSHA384
-com.android.org.conscrypt.OpenSSLMac$HmacSHA512
-com.android.org.conscrypt.OpenSSLMessageDigestJDK
-com.android.org.conscrypt.OpenSSLMessageDigestJDK$MD5
-com.android.org.conscrypt.OpenSSLMessageDigestJDK$SHA1
 com.android.org.conscrypt.OpenSSLProvider
-com.android.org.conscrypt.OpenSSLRSAKeyFactory
-com.android.org.conscrypt.OpenSSLRSAKeyPairGenerator
-com.android.org.conscrypt.OpenSSLRSAPublicKey
-com.android.org.conscrypt.OpenSSLRandom
-com.android.org.conscrypt.OpenSSLSessionImpl
-com.android.org.conscrypt.OpenSSLSignature
-com.android.org.conscrypt.OpenSSLSignature$1
-com.android.org.conscrypt.OpenSSLSignature$EngineType
-com.android.org.conscrypt.OpenSSLSignature$MD5RSA
-com.android.org.conscrypt.OpenSSLSignature$SHA1DSA
-com.android.org.conscrypt.OpenSSLSignature$SHA1ECDSA
-com.android.org.conscrypt.OpenSSLSignature$SHA1RSA
-com.android.org.conscrypt.OpenSSLSignature$SHA256ECDSA
-com.android.org.conscrypt.OpenSSLSignature$SHA256RSA
-com.android.org.conscrypt.OpenSSLSignature$SHA384ECDSA
-com.android.org.conscrypt.OpenSSLSignature$SHA384RSA
-com.android.org.conscrypt.OpenSSLSignature$SHA512ECDSA
-com.android.org.conscrypt.OpenSSLSignature$SHA512RSA
-com.android.org.conscrypt.OpenSSLSignatureRawRSA
-com.android.org.conscrypt.OpenSSLSocketFactoryImpl
 com.android.org.conscrypt.OpenSSLSocketImpl
-com.android.org.conscrypt.OpenSSLSocketImpl$SSLInputStream
-com.android.org.conscrypt.OpenSSLSocketImpl$SSLOutputStream
-com.android.org.conscrypt.OpenSSLSocketImplWrapper
-com.android.org.conscrypt.OpenSSLX509CertPath
-com.android.org.conscrypt.OpenSSLX509CertPath$Encoding
-com.android.org.conscrypt.OpenSSLX509Certificate
-com.android.org.conscrypt.OpenSSLX509CertificateFactory
-com.android.org.conscrypt.OpenSSLX509CertificateFactory$1
-com.android.org.conscrypt.OpenSSLX509CertificateFactory$2
-com.android.org.conscrypt.OpenSSLX509CertificateFactory$Parser
-com.android.org.conscrypt.ProtocolVersion
-com.android.org.conscrypt.SSLClientSessionCache
-com.android.org.conscrypt.SSLContextImpl
-com.android.org.conscrypt.SSLParametersImpl
-com.android.org.conscrypt.ServerSessionContext
+com.android.org.conscrypt.Platform
+com.android.org.conscrypt.Platform$OpenSSLMapper
 com.android.org.conscrypt.TrustManagerFactoryImpl
-com.android.org.conscrypt.TrustManagerImpl
-com.android.org.conscrypt.TrustManagerImpl$ExtendedKeyUsagePKIXCertPathChecker
-com.android.org.conscrypt.TrustedCertificateIndex
 com.android.org.conscrypt.TrustedCertificateKeyStoreSpi
-com.android.org.conscrypt.TrustedCertificateStore
-com.android.org.conscrypt.TrustedCertificateStore$1
-com.android.org.conscrypt.TrustedCertificateStore$2
-com.android.org.conscrypt.TrustedCertificateStore$3
-com.android.org.conscrypt.TrustedCertificateStore$CertSelector
 com.android.server.NetworkManagementSocketTagger
 com.android.server.NetworkManagementSocketTagger$1
-com.android.server.NetworkManagementSocketTagger$SocketTags
 com.android.server.Watchdog
 com.google.android.collect.Lists
 com.google.android.collect.Maps
-com.google.android.gles_jni.EGLConfigImpl
-com.google.android.gles_jni.EGLContextImpl
-com.google.android.gles_jni.EGLDisplayImpl
 com.google.android.gles_jni.EGLImpl
-com.google.android.gles_jni.EGLSurfaceImpl
 com.google.android.gles_jni.GLImpl
 dalvik.system.BaseDexClassLoader
 dalvik.system.BlockGuard
@@ -1751,47 +998,36 @@
 java.beans.PropertyChangeEvent
 java.beans.PropertyChangeSupport
 java.io.BufferedInputStream
-java.io.BufferedOutputStream
 java.io.BufferedReader
-java.io.BufferedWriter
 java.io.ByteArrayInputStream
 java.io.ByteArrayOutputStream
+java.io.CharArrayWriter
 java.io.Closeable
 java.io.Console
 java.io.DataInput
 java.io.DataInputStream
 java.io.DataOutput
 java.io.DataOutputStream
-java.io.Externalizable
 java.io.File
 java.io.FileDescriptor
-java.io.FileFilter
 java.io.FileInputStream
 java.io.FileNotFoundException
 java.io.FileOutputStream
-java.io.FileReader
 java.io.FilterInputStream
 java.io.FilterOutputStream
-java.io.FilterReader
 java.io.Flushable
 java.io.IOException
 java.io.InputStream
 java.io.InputStreamReader
-java.io.ObjectInput
-java.io.ObjectInputStream
 java.io.ObjectStreamClass
-java.io.ObjectStreamConstants
 java.io.ObjectStreamField
 java.io.OutputStream
 java.io.OutputStreamWriter
 java.io.PrintStream
 java.io.PrintWriter
-java.io.PushbackInputStream
-java.io.PushbackReader
 java.io.RandomAccessFile
 java.io.Reader
 java.io.Serializable
-java.io.StringReader
 java.io.StringWriter
 java.io.Writer
 java.lang.AbstractMethodError
@@ -1800,6 +1036,7 @@
 java.lang.ArithmeticException
 java.lang.ArrayIndexOutOfBoundsException
 java.lang.ArrayStoreException
+java.lang.AssertionError
 java.lang.AutoCloseable
 java.lang.Boolean
 java.lang.BootClassLoader
@@ -1807,7 +1044,6 @@
 java.lang.CaseMapper
 java.lang.CharSequence
 java.lang.Character
-java.lang.Character$UnicodeBlock
 java.lang.Class
 java.lang.ClassCastException
 java.lang.ClassCircularityError
@@ -1815,6 +1051,7 @@
 java.lang.ClassLoader
 java.lang.ClassLoader$SystemClassLoader
 java.lang.ClassNotFoundException
+java.lang.CloneNotSupportedException
 java.lang.Cloneable
 java.lang.Comparable
 java.lang.Daemons
@@ -1853,15 +1090,16 @@
 java.lang.NoSuchFieldError
 java.lang.NoSuchFieldException
 java.lang.NoSuchMethodError
-java.lang.NoSuchMethodException
 java.lang.NullPointerException
 java.lang.Number
 java.lang.NumberFormatException
 java.lang.Object
 java.lang.OutOfMemoryError
+java.lang.Package
 java.lang.Readable
 java.lang.RealToString
 java.lang.RealToString$1
+java.lang.ReflectiveOperationException
 java.lang.Runnable
 java.lang.Runtime
 java.lang.RuntimeException
@@ -1877,8 +1115,8 @@
 java.lang.StringBuilder
 java.lang.StringIndexOutOfBoundsException
 java.lang.StringToReal
-java.lang.StringToReal$StringExponentPair
 java.lang.System
+java.lang.System$PropertiesWithNonOverrideableDefaults
 java.lang.Thread
 java.lang.Thread$State
 java.lang.Thread$UncaughtExceptionHandler
@@ -1887,10 +1125,10 @@
 java.lang.ThreadLocal$Values
 java.lang.Throwable
 java.lang.TypeNotPresentException
-java.lang.UnsafeByteSequence
 java.lang.UnsatisfiedLinkError
 java.lang.UnsupportedOperationException
 java.lang.VMClassLoader
+java.lang.VMThread
 java.lang.VerifyError
 java.lang.VirtualMachineError
 java.lang.Void
@@ -1915,31 +1153,19 @@
 java.lang.reflect.Modifier
 java.lang.reflect.Proxy
 java.lang.reflect.Type
+java.lang.reflect.TypeVariable
 java.math.BigDecimal
-java.math.BigInt
 java.math.BigInteger
 java.math.NativeBN
-java.math.RoundingMode
 java.net.AddressCache
-java.net.AddressCache$AddressCacheEntry
-java.net.CacheResponse
 java.net.ContentHandler
-java.net.CookieHandler
-java.net.HttpURLConnection
-java.net.Inet4Address
 java.net.Inet6Address
 java.net.InetAddress
 java.net.InetSocketAddress
 java.net.InetUnixAddress
 java.net.JarURLConnection
-java.net.PlainSocketImpl
-java.net.PlainSocketImpl$PlainSocketInputStream
-java.net.PlainSocketImpl$PlainSocketOutputStream
-java.net.Proxy
-java.net.Proxy$Type
 java.net.ProxySelector
 java.net.ProxySelectorImpl
-java.net.ResponseCache
 java.net.Socket
 java.net.SocketAddress
 java.net.SocketImpl
@@ -1947,11 +1173,10 @@
 java.net.URI
 java.net.URI$1
 java.net.URI$PartEncoder
+java.net.URISyntaxException
 java.net.URL
 java.net.URLConnection
 java.net.URLConnection$DefaultContentHandler
-java.net.URLEncoder
-java.net.URLEncoder$1
 java.net.URLStreamHandler
 java.net.UnknownHostException
 java.nio.Buffer
@@ -1965,8 +1190,6 @@
 java.nio.FileChannelImpl
 java.nio.FileChannelImpl$1
 java.nio.MappedByteBuffer
-java.nio.MemoryBlock
-java.nio.MemoryBlock$NonMovableHeapBlock
 java.nio.NIOAccess
 java.nio.NioUtils
 java.nio.channels.ByteChannel
@@ -1988,93 +1211,37 @@
 java.nio.charset.Charsets
 java.nio.charset.CoderResult
 java.nio.charset.CodingErrorAction
-java.nio.charset.ModifiedUtf8
+java.nio.charset.StandardCharsets
 java.security.AccessController
 java.security.BasicPermission
 java.security.Guard
 java.security.Key
-java.security.KeyFactory
 java.security.KeyFactorySpi
-java.security.KeyPairGenerator
 java.security.KeyPairGeneratorSpi
-java.security.KeyStore
 java.security.KeyStoreSpi
-java.security.MessageDigest
-java.security.MessageDigestSpi
 java.security.Permission
-java.security.Principal
 java.security.PrivilegedAction
 java.security.Provider
 java.security.Provider$Service
 java.security.PublicKey
-java.security.SecureRandom
-java.security.SecureRandomSpi
 java.security.Security
 java.security.Security$SecurityDoor
-java.security.Signature
-java.security.SignatureSpi
-java.security.cert.CertPath
-java.security.cert.CertPathParameters
-java.security.cert.CertPathValidator
-java.security.cert.CertPathValidatorResult
-java.security.cert.CertPathValidatorSpi
-java.security.cert.CertSelector
+java.security.cert.CertStoreParameters
 java.security.cert.Certificate
 java.security.cert.CertificateFactory
-java.security.cert.CertificateFactorySpi
-java.security.cert.CertStoreParameters
-java.security.cert.PKIXCertPathChecker
-java.security.cert.PKIXCertPathValidatorResult
-java.security.cert.PKIXParameters
-java.security.cert.PolicyNode
-java.security.cert.TrustAnchor
-java.security.cert.X509CertSelector
-java.security.cert.X509Certificate
-java.security.cert.X509Extension
-java.security.interfaces.DSAKey
-java.security.interfaces.DSAPublicKey
-java.security.interfaces.RSAKey
-java.security.interfaces.RSAPublicKey
-java.security.spec.AlgorithmParameterSpec
-java.security.spec.EncodedKeySpec
-java.security.spec.KeySpec
-java.security.spec.RSAPublicKeySpec
-java.security.spec.X509EncodedKeySpec
-java.sql.Date
-java.text.AttributedCharacterIterator$Attribute
 java.text.Bidi
 java.text.Bidi$Run
-java.text.Collator
-java.text.DateFormat
-java.text.DateFormat$Field
-java.text.DateFormatSymbols
-java.text.DecimalFormat
-java.text.DecimalFormatSymbols
-java.text.FieldPosition
-java.text.Format
-java.text.Format$Field
-java.text.NumberFormat
-java.text.NumberFormat$Field
 java.text.ParsePosition
-java.text.RuleBasedCollator
-java.text.SimpleDateFormat
 java.util.AbstractCollection
 java.util.AbstractList
-java.util.AbstractList$FullListIterator
 java.util.AbstractList$SimpleListIterator
-java.util.AbstractList$SubAbstractList
-java.util.AbstractList$SubAbstractList$SubAbstractListIterator
-java.util.AbstractList$SubAbstractListRandomAccess
 java.util.AbstractMap
 java.util.AbstractQueue
-java.util.AbstractSequentialList
 java.util.AbstractSet
 java.util.ArrayDeque
 java.util.ArrayList
 java.util.ArrayList$ArrayListIterator
 java.util.Arrays
-java.util.Arrays$ArrayList
-java.util.BitSet
 java.util.Calendar
 java.util.Collection
 java.util.Collections
@@ -2083,36 +1250,16 @@
 java.util.Collections$EmptyList
 java.util.Collections$EmptyMap
 java.util.Collections$EmptySet
-java.util.Collections$SingletonList
-java.util.Collections$SynchronizedCollection
-java.util.Collections$SynchronizedMap
-java.util.Collections$SynchronizedSet
 java.util.Collections$UnmodifiableCollection
 java.util.Collections$UnmodifiableCollection$1
-java.util.Collections$UnmodifiableList
-java.util.Collections$UnmodifiableMap
-java.util.Collections$UnmodifiableMap$UnmodifiableEntrySet
-java.util.Collections$UnmodifiableMap$UnmodifiableEntrySet$1
-java.util.Collections$UnmodifiableMap$UnmodifiableEntrySet$UnmodifiableMapEntry
-java.util.Collections$UnmodifiableRandomAccessList
 java.util.Collections$UnmodifiableSet
-java.util.ComparableTimSort
 java.util.Comparator
-java.util.Currency
-java.util.Date
 java.util.Deque
 java.util.Dictionary
-java.util.EnumMap
-java.util.EnumSet
 java.util.Enumeration
 java.util.EventObject
-java.util.Formattable
 java.util.Formatter
 java.util.Formatter$1
-java.util.Formatter$CachedDecimalFormat
-java.util.Formatter$FormatSpecifierParser
-java.util.Formatter$FormatToken
-java.util.GregorianCalendar
 java.util.HashMap
 java.util.HashMap$EntryIterator
 java.util.HashMap$EntrySet
@@ -2120,12 +1267,9 @@
 java.util.HashMap$HashMapEntry
 java.util.HashMap$KeyIterator
 java.util.HashMap$KeySet
-java.util.HashMap$ValueIterator
 java.util.HashMap$Values
 java.util.HashSet
 java.util.Hashtable
-java.util.Hashtable$EntryIterator
-java.util.Hashtable$EntrySet
 java.util.Hashtable$HashIterator
 java.util.Hashtable$HashtableEntry
 java.util.Hashtable$KeyEnumeration
@@ -2139,17 +1283,14 @@
 java.util.LinkedHashMap$LinkedHashIterator
 java.util.LinkedHashMap$ValueIterator
 java.util.LinkedHashSet
-java.util.LinkedList
-java.util.LinkedList$Link
-java.util.LinkedList$LinkIterator
 java.util.List
 java.util.ListIterator
 java.util.Locale
 java.util.Map
 java.util.Map$Entry
-java.util.MiniEnumSet
 java.util.NavigableMap
 java.util.NavigableSet
+java.util.Objects
 java.util.Properties
 java.util.Queue
 java.util.Random
@@ -2158,73 +1299,28 @@
 java.util.SimpleTimeZone
 java.util.SortedMap
 java.util.SortedSet
-java.util.Stack
 java.util.StringTokenizer
-java.util.TimSort
 java.util.TimeZone
-java.util.Timer
-java.util.Timer$FinalizerHelper
-java.util.Timer$TimerImpl
-java.util.Timer$TimerImpl$TimerHeap
-java.util.TimerTask
 java.util.TreeMap
 java.util.TreeMap$1
-java.util.TreeMap$2
-java.util.TreeMap$Bound
-java.util.TreeMap$Bound$1
-java.util.TreeMap$Bound$2
-java.util.TreeMap$Bound$3
-java.util.TreeMap$EntrySet
-java.util.TreeMap$EntrySet$1
-java.util.TreeMap$KeySet
-java.util.TreeMap$KeySet$1
-java.util.TreeMap$MapIterator
-java.util.TreeMap$Node
-java.util.TreeMap$Relation
 java.util.TreeSet
-java.util.UUID
-java.util.Vector
-java.util.Vector$1
 java.util.WeakHashMap
-java.util.WeakHashMap$2
-java.util.WeakHashMap$2$1
 java.util.WeakHashMap$Entry
-java.util.WeakHashMap$Entry$Type
-java.util.WeakHashMap$HashIterator
 java.util.concurrent.AbstractExecutorService
 java.util.concurrent.BlockingQueue
-java.util.concurrent.Callable
-java.util.concurrent.CancellationException
 java.util.concurrent.ConcurrentHashMap
-java.util.concurrent.ConcurrentHashMap$HashEntry
-java.util.concurrent.ConcurrentHashMap$HashIterator
-java.util.concurrent.ConcurrentHashMap$Segment
 java.util.concurrent.ConcurrentLinkedQueue
 java.util.concurrent.ConcurrentLinkedQueue$Node
-java.util.concurrent.ConcurrentMap
 java.util.concurrent.CopyOnWriteArrayList
 java.util.concurrent.CopyOnWriteArrayList$CowIterator
-java.util.concurrent.CountDownLatch
-java.util.concurrent.CountDownLatch$Sync
-java.util.concurrent.ExecutionException
 java.util.concurrent.Executor
 java.util.concurrent.ExecutorService
-java.util.concurrent.Executors
-java.util.concurrent.Executors$DefaultThreadFactory
-java.util.concurrent.Executors$DelegatedExecutorService
-java.util.concurrent.Executors$FinalizableDelegatedExecutorService
-java.util.concurrent.Executors$RunnableAdapter
-java.util.concurrent.Future
-java.util.concurrent.FutureTask
-java.util.concurrent.FutureTask$WaitNode
 java.util.concurrent.LinkedBlockingQueue
 java.util.concurrent.LinkedBlockingQueue$Node
 java.util.concurrent.RejectedExecutionHandler
-java.util.concurrent.RunnableFuture
 java.util.concurrent.ThreadFactory
 java.util.concurrent.ThreadPoolExecutor
 java.util.concurrent.ThreadPoolExecutor$AbortPolicy
-java.util.concurrent.ThreadPoolExecutor$Worker
 java.util.concurrent.TimeUnit
 java.util.concurrent.TimeUnit$1
 java.util.concurrent.TimeUnit$2
@@ -2242,24 +1338,17 @@
 java.util.concurrent.locks.AbstractQueuedSynchronizer$Node
 java.util.concurrent.locks.Condition
 java.util.concurrent.locks.Lock
-java.util.concurrent.locks.LockSupport
-java.util.concurrent.locks.ReadWriteLock
 java.util.concurrent.locks.ReentrantLock
 java.util.concurrent.locks.ReentrantLock$NonfairSync
 java.util.concurrent.locks.ReentrantLock$Sync
-java.util.concurrent.locks.ReentrantReadWriteLock
-java.util.concurrent.locks.ReentrantReadWriteLock$NonfairSync
-java.util.concurrent.locks.ReentrantReadWriteLock$ReadLock
-java.util.concurrent.locks.ReentrantReadWriteLock$Sync
-java.util.concurrent.locks.ReentrantReadWriteLock$Sync$ThreadLocalHoldCounter
-java.util.concurrent.locks.ReentrantReadWriteLock$WriteLock
 java.util.jar.Attributes
 java.util.jar.Attributes$Name
 java.util.jar.JarEntry
 java.util.jar.JarFile
-java.util.jar.JarFile$1JarFileEnumerator
-java.util.jar.JarVerifier
+java.util.jar.JarFile$JarFileEnumerator
 java.util.jar.Manifest
+java.util.jar.ManifestReader
+java.util.jar.StrictJarFile
 java.util.logging.ConsoleHandler
 java.util.logging.ErrorManager
 java.util.logging.Formatter
@@ -2281,9 +1370,6 @@
 java.util.zip.CRC32
 java.util.zip.Checksum
 java.util.zip.Deflater
-java.util.zip.DeflaterOutputStream
-java.util.zip.GZIPInputStream
-java.util.zip.GZIPOutputStream
 java.util.zip.Inflater
 java.util.zip.InflaterInputStream
 java.util.zip.ZipConstants
@@ -2292,14 +1378,6 @@
 java.util.zip.ZipFile$1
 java.util.zip.ZipFile$RAFStream
 java.util.zip.ZipFile$ZipInflaterInputStream
-javax.crypto.Cipher
-javax.crypto.CipherSpi
-javax.crypto.KeyAgreementSpi
-javax.crypto.MacSpi
-javax.crypto.SecretKey
-javax.crypto.spec.GCMParameterSpec
-javax.crypto.spec.IvParameterSpec
-javax.crypto.spec.SecretKeySpec
 javax.microedition.khronos.egl.EGL
 javax.microedition.khronos.egl.EGL10
 javax.microedition.khronos.egl.EGLConfig
@@ -2312,27 +1390,12 @@
 javax.microedition.khronos.opengles.GL11
 javax.microedition.khronos.opengles.GL11Ext
 javax.microedition.khronos.opengles.GL11ExtensionPack
-javax.net.SocketFactory
-javax.net.ssl.DefaultHostnameVerifier
-javax.net.ssl.HostnameVerifier
-javax.net.ssl.HttpsURLConnection
-javax.net.ssl.KeyManager
-javax.net.ssl.KeyManagerFactory
 javax.net.ssl.KeyManagerFactorySpi
-javax.net.ssl.SSLContextSpi
-javax.net.ssl.SSLSession
-javax.net.ssl.SSLSessionContext
 javax.net.ssl.SSLSocket
-javax.net.ssl.SSLSocketFactory
-javax.net.ssl.TrustManager
-javax.net.ssl.TrustManagerFactory
 javax.net.ssl.TrustManagerFactorySpi
-javax.net.ssl.X509ExtendedKeyManager
-javax.net.ssl.X509KeyManager
-javax.net.ssl.X509TrustManager
-javax.security.auth.x500.X500Principal
 libcore.icu.AlphabeticIndex
 libcore.icu.AlphabeticIndex$ImmutableIndex
+libcore.icu.DateIntervalFormat
 libcore.icu.ICU
 libcore.icu.LocaleData
 libcore.icu.NativeBreakIterator
@@ -2343,10 +1406,8 @@
 libcore.icu.NativeIDN
 libcore.icu.NativeNormalizer
 libcore.icu.NativePluralRules
-libcore.icu.RuleBasedCollatorICU
 libcore.icu.TimeZoneNames
 libcore.icu.Transliterator
-libcore.internal.StringPool
 libcore.io.AsynchronousCloseMonitor
 libcore.io.BlockGuardOs
 libcore.io.BufferIterator
@@ -2364,8 +1425,6 @@
 libcore.io.IoUtils
 libcore.io.Libcore
 libcore.io.Memory
-libcore.io.MemoryMappedFile
-libcore.io.NioBufferIterator
 libcore.io.Os
 libcore.io.OsConstants
 libcore.io.Posix
@@ -2377,21 +1436,19 @@
 libcore.io.StructPasswd
 libcore.io.StructPollfd
 libcore.io.StructStat
+libcore.io.StructStatVfs
 libcore.io.StructTimeval
 libcore.io.StructUcred
 libcore.io.StructUtsname
-libcore.math.MathUtils
-libcore.net.MimeUtils
-libcore.net.RawSocket
 libcore.net.UriCodec
-libcore.net.http.HttpDate
-libcore.net.http.HttpDate$1
 libcore.net.url.FileHandler
 libcore.net.url.FileURLConnection
 libcore.net.url.JarHandler
 libcore.net.url.JarURLConnectionImpl
 libcore.net.url.JarURLConnectionImpl$JarURLConnectionInputStream
 libcore.net.url.UrlUtils
+libcore.reflect.AnnotationFactory
+libcore.reflect.AnnotationMember
 libcore.util.BasicLruCache
 libcore.util.CollectionUtils
 libcore.util.CollectionUtils$1
@@ -2400,371 +1457,29 @@
 libcore.util.MutableInt
 libcore.util.MutableLong
 libcore.util.Objects
-libcore.util.ZoneInfo
 libcore.util.ZoneInfoDB
-org.apache.commons.logging.Log
-org.apache.commons.logging.LogFactory
-org.apache.commons.logging.impl.Jdk14Logger
-org.apache.commons.logging.impl.WeakHashtable
-org.apache.harmony.crypto.internal.NullCipherSpi
 org.apache.harmony.dalvik.NativeTestTarget
 org.apache.harmony.dalvik.ddmc.Chunk
 org.apache.harmony.dalvik.ddmc.ChunkHandler
 org.apache.harmony.dalvik.ddmc.DdmServer
 org.apache.harmony.luni.internal.util.TimezoneGetter
-org.apache.harmony.security.asn1.ASN1Any
-org.apache.harmony.security.asn1.ASN1BitString
-org.apache.harmony.security.asn1.ASN1BitString$ASN1NamedBitList
-org.apache.harmony.security.asn1.ASN1Boolean
-org.apache.harmony.security.asn1.ASN1Choice
-org.apache.harmony.security.asn1.ASN1Constants
-org.apache.harmony.security.asn1.ASN1Constructed
-org.apache.harmony.security.asn1.ASN1Explicit
-org.apache.harmony.security.asn1.ASN1GeneralizedTime
-org.apache.harmony.security.asn1.ASN1Implicit
-org.apache.harmony.security.asn1.ASN1Integer
-org.apache.harmony.security.asn1.ASN1OctetString
-org.apache.harmony.security.asn1.ASN1Oid
-org.apache.harmony.security.asn1.ASN1Oid$1
-org.apache.harmony.security.asn1.ASN1Primitive
-org.apache.harmony.security.asn1.ASN1Sequence
-org.apache.harmony.security.asn1.ASN1SequenceOf
-org.apache.harmony.security.asn1.ASN1SetOf
 org.apache.harmony.security.asn1.ASN1StringType
-org.apache.harmony.security.asn1.ASN1StringType$1
-org.apache.harmony.security.asn1.ASN1StringType$2
-org.apache.harmony.security.asn1.ASN1StringType$3
-org.apache.harmony.security.asn1.ASN1StringType$4
-org.apache.harmony.security.asn1.ASN1StringType$5
-org.apache.harmony.security.asn1.ASN1StringType$6
-org.apache.harmony.security.asn1.ASN1StringType$7
-org.apache.harmony.security.asn1.ASN1StringType$ASN1StringUTF8Type
-org.apache.harmony.security.asn1.ASN1Time
-org.apache.harmony.security.asn1.ASN1Type
-org.apache.harmony.security.asn1.ASN1TypeCollection
-org.apache.harmony.security.asn1.ASN1UTCTime
-org.apache.harmony.security.asn1.ASN1ValueCollection
-org.apache.harmony.security.asn1.BerInputStream
-org.apache.harmony.security.asn1.BerOutputStream
-org.apache.harmony.security.asn1.BitString
-org.apache.harmony.security.asn1.DerInputStream
-org.apache.harmony.security.asn1.DerOutputStream
-org.apache.harmony.security.asn1.ObjectIdentifier
 org.apache.harmony.security.fortress.Engine
-org.apache.harmony.security.fortress.Engine$ServiceCacheEntry
-org.apache.harmony.security.fortress.Engine$SpiAndProvider
 org.apache.harmony.security.fortress.SecurityAccess
 org.apache.harmony.security.fortress.Services
+org.apache.harmony.security.provider.cert.DRLCertFactory
 org.apache.harmony.security.provider.crypto.CryptoProvider
 org.apache.harmony.security.utils.AlgNameMapper
-org.apache.harmony.security.utils.ObjectIdentifier
+org.apache.harmony.security.utils.AlgNameMapperSource
 org.apache.harmony.security.x501.AttributeTypeAndValue
-org.apache.harmony.security.x501.AttributeTypeAndValue$1
-org.apache.harmony.security.x501.AttributeTypeAndValue$2
-org.apache.harmony.security.x501.AttributeTypeAndValueComparator
-org.apache.harmony.security.x501.AttributeValue
 org.apache.harmony.security.x501.DirectoryString
-org.apache.harmony.security.x501.DirectoryString$1
 org.apache.harmony.security.x501.Name
-org.apache.harmony.security.x501.Name$1
-org.apache.harmony.security.x509.AlgorithmIdentifier
-org.apache.harmony.security.x509.AlgorithmIdentifier$1
-org.apache.harmony.security.x509.BasicConstraints
-org.apache.harmony.security.x509.BasicConstraints$1
-org.apache.harmony.security.x509.Certificate
-org.apache.harmony.security.x509.Certificate$1
-org.apache.harmony.security.x509.EDIPartyName
-org.apache.harmony.security.x509.EDIPartyName$1
-org.apache.harmony.security.x509.ExtendedKeyUsage
-org.apache.harmony.security.x509.ExtendedKeyUsage$1
-org.apache.harmony.security.x509.Extension
-org.apache.harmony.security.x509.Extension$1
-org.apache.harmony.security.x509.Extension$2
-org.apache.harmony.security.x509.ExtensionValue
-org.apache.harmony.security.x509.Extensions
-org.apache.harmony.security.x509.Extensions$1
-org.apache.harmony.security.x509.GeneralName
-org.apache.harmony.security.x509.GeneralName$1
-org.apache.harmony.security.x509.GeneralName$2
-org.apache.harmony.security.x509.GeneralNames
-org.apache.harmony.security.x509.GeneralNames$1
-org.apache.harmony.security.x509.KeyUsage
-org.apache.harmony.security.x509.ORAddress
-org.apache.harmony.security.x509.ORAddress$1
-org.apache.harmony.security.x509.ORAddress$2
-org.apache.harmony.security.x509.OtherName
-org.apache.harmony.security.x509.OtherName$1
-org.apache.harmony.security.x509.SubjectPublicKeyInfo
-org.apache.harmony.security.x509.SubjectPublicKeyInfo$1
-org.apache.harmony.security.x509.TBSCertificate
-org.apache.harmony.security.x509.TBSCertificate$1
-org.apache.harmony.security.x509.Time
-org.apache.harmony.security.x509.Time$1
-org.apache.harmony.security.x509.Validity
-org.apache.harmony.security.x509.Validity$1
 org.apache.harmony.xml.ExpatAttributes
 org.apache.harmony.xml.ExpatParser
-org.apache.http.ConnectionReuseStrategy
-org.apache.http.FormattedHeader
-org.apache.http.Header
-org.apache.http.HeaderElement
-org.apache.http.HeaderElementIterator
-org.apache.http.HeaderIterator
-org.apache.http.HttpClientConnection
-org.apache.http.HttpConnection
-org.apache.http.HttpConnectionMetrics
-org.apache.http.HttpEntity
-org.apache.http.HttpEntityEnclosingRequest
-org.apache.http.HttpHost
-org.apache.http.HttpInetConnection
-org.apache.http.HttpMessage
-org.apache.http.HttpRequest
-org.apache.http.HttpRequestInterceptor
-org.apache.http.HttpResponse
-org.apache.http.HttpResponseFactory
-org.apache.http.HttpResponseInterceptor
-org.apache.http.HttpVersion
-org.apache.http.NameValuePair
-org.apache.http.ProtocolVersion
-org.apache.http.ReasonPhraseCatalog
-org.apache.http.RequestLine
-org.apache.http.StatusLine
-org.apache.http.auth.AuthSchemeFactory
-org.apache.http.auth.AuthSchemeRegistry
-org.apache.http.auth.AuthState
-org.apache.http.client.AuthenticationHandler
-org.apache.http.client.CookieStore
-org.apache.http.client.CredentialsProvider
-org.apache.http.client.HttpClient
-org.apache.http.client.HttpRequestRetryHandler
-org.apache.http.client.RedirectHandler
-org.apache.http.client.RequestDirector
-org.apache.http.client.ResponseHandler
-org.apache.http.client.UserTokenHandler
-org.apache.http.client.methods.AbortableHttpRequest
-org.apache.http.client.methods.HttpEntityEnclosingRequestBase
-org.apache.http.client.methods.HttpGet
-org.apache.http.client.methods.HttpPost
-org.apache.http.client.methods.HttpRequestBase
-org.apache.http.client.methods.HttpUriRequest
-org.apache.http.client.params.HttpClientParams
-org.apache.http.client.protocol.RequestAddCookies
-org.apache.http.client.protocol.RequestDefaultHeaders
-org.apache.http.client.protocol.RequestProxyAuthentication
-org.apache.http.client.protocol.RequestTargetAuthentication
-org.apache.http.client.protocol.ResponseProcessCookies
-org.apache.http.client.utils.URIUtils
-org.apache.http.conn.BasicManagedEntity
-org.apache.http.conn.ClientConnectionManager
-org.apache.http.conn.ClientConnectionOperator
-org.apache.http.conn.ClientConnectionRequest
-org.apache.http.conn.ConnectionKeepAliveStrategy
-org.apache.http.conn.ConnectionReleaseTrigger
-org.apache.http.conn.EofSensorInputStream
-org.apache.http.conn.EofSensorWatcher
-org.apache.http.conn.ManagedClientConnection
-org.apache.http.conn.OperatedClientConnection
-org.apache.http.conn.params.ConnManagerPNames
-org.apache.http.conn.params.ConnManagerParams
-org.apache.http.conn.params.ConnManagerParams$1
-org.apache.http.conn.params.ConnPerRoute
-org.apache.http.conn.params.ConnPerRouteBean
-org.apache.http.conn.params.ConnRoutePNames
-org.apache.http.conn.params.ConnRouteParams
-org.apache.http.conn.routing.BasicRouteDirector
-org.apache.http.conn.routing.HttpRoute
-org.apache.http.conn.routing.HttpRouteDirector
-org.apache.http.conn.routing.HttpRoutePlanner
-org.apache.http.conn.routing.RouteInfo
-org.apache.http.conn.routing.RouteInfo$LayerType
-org.apache.http.conn.routing.RouteInfo$TunnelType
-org.apache.http.conn.routing.RouteTracker
-org.apache.http.conn.scheme.LayeredSocketFactory
-org.apache.http.conn.scheme.PlainSocketFactory
-org.apache.http.conn.scheme.Scheme
-org.apache.http.conn.scheme.SchemeRegistry
-org.apache.http.conn.scheme.SocketFactory
-org.apache.http.conn.ssl.AbstractVerifier
-org.apache.http.conn.ssl.AllowAllHostnameVerifier
-org.apache.http.conn.ssl.BrowserCompatHostnameVerifier
-org.apache.http.conn.ssl.SSLSocketFactory
-org.apache.http.conn.ssl.StrictHostnameVerifier
-org.apache.http.conn.ssl.X509HostnameVerifier
 org.apache.http.conn.util.InetAddressUtils
-org.apache.http.cookie.CookieAttributeHandler
-org.apache.http.cookie.CookieIdentityComparator
-org.apache.http.cookie.CookieOrigin
-org.apache.http.cookie.CookiePathComparator
-org.apache.http.cookie.CookieSpec
-org.apache.http.cookie.CookieSpecFactory
-org.apache.http.cookie.CookieSpecRegistry
-org.apache.http.entity.AbstractHttpEntity
-org.apache.http.entity.BasicHttpEntity
-org.apache.http.entity.ByteArrayEntity
-org.apache.http.entity.ContentLengthStrategy
-org.apache.http.entity.HttpEntityWrapper
-org.apache.http.impl.AbstractHttpClientConnection
-org.apache.http.impl.DefaultConnectionReuseStrategy
-org.apache.http.impl.DefaultHttpResponseFactory
 org.apache.http.impl.EnglishReasonPhraseCatalog
-org.apache.http.impl.HttpConnectionMetricsImpl
-org.apache.http.impl.SocketHttpClientConnection
-org.apache.http.impl.auth.BasicSchemeFactory
-org.apache.http.impl.auth.DigestSchemeFactory
-org.apache.http.impl.client.AbstractAuthenticationHandler
-org.apache.http.impl.client.AbstractHttpClient
-org.apache.http.impl.client.BasicCookieStore
-org.apache.http.impl.client.BasicCredentialsProvider
-org.apache.http.impl.client.ClientParamsStack
-org.apache.http.impl.client.DefaultConnectionKeepAliveStrategy
-org.apache.http.impl.client.DefaultHttpClient
-org.apache.http.impl.client.DefaultHttpRequestRetryHandler
-org.apache.http.impl.client.DefaultProxyAuthenticationHandler
-org.apache.http.impl.client.DefaultRedirectHandler
-org.apache.http.impl.client.DefaultRequestDirector
-org.apache.http.impl.client.DefaultTargetAuthenticationHandler
-org.apache.http.impl.client.DefaultUserTokenHandler
-org.apache.http.impl.client.EntityEnclosingRequestWrapper
-org.apache.http.impl.client.RequestWrapper
-org.apache.http.impl.client.RoutedRequest
-org.apache.http.impl.conn.AbstractClientConnAdapter
-org.apache.http.impl.conn.AbstractPoolEntry
-org.apache.http.impl.conn.AbstractPooledConnAdapter
-org.apache.http.impl.conn.DefaultClientConnection
-org.apache.http.impl.conn.DefaultClientConnectionOperator
-org.apache.http.impl.conn.DefaultResponseParser
-org.apache.http.impl.conn.IdleConnectionHandler
-org.apache.http.impl.conn.IdleConnectionHandler$TimeValues
-org.apache.http.impl.conn.ProxySelectorRoutePlanner
-org.apache.http.impl.conn.ProxySelectorRoutePlanner$1
-org.apache.http.impl.conn.tsccm.AbstractConnPool
-org.apache.http.impl.conn.tsccm.BasicPoolEntry
-org.apache.http.impl.conn.tsccm.BasicPoolEntryRef
-org.apache.http.impl.conn.tsccm.BasicPooledConnAdapter
-org.apache.http.impl.conn.tsccm.ConnPoolByRoute
-org.apache.http.impl.conn.tsccm.ConnPoolByRoute$1
-org.apache.http.impl.conn.tsccm.PoolEntryRequest
-org.apache.http.impl.conn.tsccm.RefQueueHandler
-org.apache.http.impl.conn.tsccm.RefQueueWorker
-org.apache.http.impl.conn.tsccm.RouteSpecificPool
-org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager
-org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager$1
-org.apache.http.impl.conn.tsccm.WaitingThreadAborter
-org.apache.http.impl.cookie.AbstractCookieAttributeHandler
-org.apache.http.impl.cookie.AbstractCookieSpec
-org.apache.http.impl.cookie.BasicCommentHandler
-org.apache.http.impl.cookie.BasicExpiresHandler
-org.apache.http.impl.cookie.BasicMaxAgeHandler
-org.apache.http.impl.cookie.BasicPathHandler
-org.apache.http.impl.cookie.BasicSecureHandler
-org.apache.http.impl.cookie.BestMatchSpec
-org.apache.http.impl.cookie.BestMatchSpecFactory
-org.apache.http.impl.cookie.BrowserCompatSpecFactory
-org.apache.http.impl.cookie.CookieSpecBase
-org.apache.http.impl.cookie.NetscapeDraftSpecFactory
-org.apache.http.impl.cookie.RFC2109DomainHandler
-org.apache.http.impl.cookie.RFC2109Spec
-org.apache.http.impl.cookie.RFC2109SpecFactory
-org.apache.http.impl.cookie.RFC2109VersionHandler
-org.apache.http.impl.cookie.RFC2965CommentUrlAttributeHandler
-org.apache.http.impl.cookie.RFC2965DiscardAttributeHandler
-org.apache.http.impl.cookie.RFC2965DomainAttributeHandler
-org.apache.http.impl.cookie.RFC2965PortAttributeHandler
-org.apache.http.impl.cookie.RFC2965Spec
-org.apache.http.impl.cookie.RFC2965SpecFactory
-org.apache.http.impl.cookie.RFC2965VersionAttributeHandler
-org.apache.http.impl.entity.EntityDeserializer
-org.apache.http.impl.entity.EntitySerializer
-org.apache.http.impl.entity.LaxContentLengthStrategy
-org.apache.http.impl.entity.StrictContentLengthStrategy
-org.apache.http.impl.io.AbstractMessageParser
-org.apache.http.impl.io.AbstractMessageWriter
-org.apache.http.impl.io.AbstractSessionInputBuffer
-org.apache.http.impl.io.AbstractSessionOutputBuffer
-org.apache.http.impl.io.ChunkedInputStream
-org.apache.http.impl.io.ContentLengthInputStream
-org.apache.http.impl.io.ContentLengthOutputStream
-org.apache.http.impl.io.HttpRequestWriter
-org.apache.http.impl.io.HttpTransportMetricsImpl
-org.apache.http.impl.io.SocketInputBuffer
-org.apache.http.impl.io.SocketOutputBuffer
-org.apache.http.io.HttpMessageParser
-org.apache.http.io.HttpMessageWriter
-org.apache.http.io.HttpTransportMetrics
-org.apache.http.io.SessionInputBuffer
-org.apache.http.io.SessionOutputBuffer
-org.apache.http.message.AbstractHttpMessage
-org.apache.http.message.BasicHeader
-org.apache.http.message.BasicHeaderElement
-org.apache.http.message.BasicHeaderElementIterator
-org.apache.http.message.BasicHeaderValueParser
-org.apache.http.message.BasicHttpResponse
-org.apache.http.message.BasicLineFormatter
-org.apache.http.message.BasicLineParser
-org.apache.http.message.BasicListHeaderIterator
-org.apache.http.message.BasicNameValuePair
-org.apache.http.message.BasicRequestLine
-org.apache.http.message.BasicStatusLine
-org.apache.http.message.BufferedHeader
-org.apache.http.message.HeaderGroup
-org.apache.http.message.HeaderValueParser
-org.apache.http.message.LineFormatter
-org.apache.http.message.LineParser
-org.apache.http.message.ParserCursor
-org.apache.http.params.AbstractHttpParams
-org.apache.http.params.BasicHttpParams
-org.apache.http.params.CoreConnectionPNames
-org.apache.http.params.CoreProtocolPNames
-org.apache.http.params.HttpConnectionParams
-org.apache.http.params.HttpParams
-org.apache.http.params.HttpProtocolParams
-org.apache.http.protocol.BasicHttpContext
-org.apache.http.protocol.BasicHttpProcessor
-org.apache.http.protocol.HTTP
-org.apache.http.protocol.HttpContext
-org.apache.http.protocol.HttpProcessor
-org.apache.http.protocol.HttpRequestExecutor
-org.apache.http.protocol.HttpRequestInterceptorList
-org.apache.http.protocol.HttpResponseInterceptorList
-org.apache.http.protocol.RequestConnControl
-org.apache.http.protocol.RequestContent
-org.apache.http.protocol.RequestExpectContinue
-org.apache.http.protocol.RequestTargetHost
-org.apache.http.protocol.RequestUserAgent
-org.apache.http.util.ByteArrayBuffer
-org.apache.http.util.CharArrayBuffer
-org.apache.http.util.LangUtils
-org.ccil.cowan.tagsoup.AttributesImpl
-org.ccil.cowan.tagsoup.AutoDetector
-org.ccil.cowan.tagsoup.Element
-org.ccil.cowan.tagsoup.ElementType
-org.ccil.cowan.tagsoup.HTMLModels
-org.ccil.cowan.tagsoup.HTMLScanner
-org.ccil.cowan.tagsoup.HTMLSchema
-org.ccil.cowan.tagsoup.Parser
-org.ccil.cowan.tagsoup.Parser$1
-org.ccil.cowan.tagsoup.ScanHandler
-org.ccil.cowan.tagsoup.Scanner
-org.ccil.cowan.tagsoup.Schema
-org.json.JSON
-org.json.JSONArray
-org.json.JSONObject
-org.json.JSONObject$1
-org.json.JSONStringer
-org.json.JSONStringer$Scope
-org.json.JSONTokener
 org.kxml2.io.KXmlParser
-org.kxml2.io.KXmlParser$ValueContext
 org.xml.sax.Attributes
-org.xml.sax.ContentHandler
-org.xml.sax.DTDHandler
-org.xml.sax.EntityResolver
-org.xml.sax.ErrorHandler
-org.xml.sax.InputSource
-org.xml.sax.Locator
-org.xml.sax.XMLReader
-org.xml.sax.ext.LexicalHandler
-org.xml.sax.helpers.DefaultHandler
 org.xmlpull.v1.XmlPullParser
-org.xmlpull.v1.XmlSerializer
+org.xmlpull.v1.XmlPullParserException
 sun.misc.Unsafe
diff --git a/services/Android.mk b/services/Android.mk
new file mode 100644
index 0000000..5260540
--- /dev/null
+++ b/services/Android.mk
@@ -0,0 +1,64 @@
+LOCAL_PATH:= $(call my-dir)
+
+# merge all required services into one jar
+# ============================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := services
+
+LOCAL_SRC_FILES := $(call all-java-files-under,java)
+
+# Uncomment to enable output of certain warnings (deprecated, unchecked)
+# LOCAL_JAVACFLAGS := -Xlint
+
+# Services that will be built as part of services.jar
+# These should map to directory names relative to this
+# Android.mk.
+services := \
+    core \
+    accessibility \
+    appwidget \
+    backup \
+    devicepolicy \
+    print \
+    usb
+
+# The convention is to name each service module 'services.$(module_name)'
+LOCAL_STATIC_JAVA_LIBRARIES := $(addprefix services.,$(services))
+
+include $(BUILD_JAVA_LIBRARY)
+
+# native library
+# =============================================================
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES :=
+LOCAL_SHARED_LIBRARIES :=
+
+# include all the jni subdirs to collect their sources
+include $(wildcard $(LOCAL_PATH)/*/jni/Android.mk)
+
+LOCAL_CFLAGS += -DEGL_EGLEXT_PROTOTYPES -DGL_GLEXT_PROTOTYPES
+
+ifeq ($(WITH_MALLOC_LEAK_CHECK),true)
+    LOCAL_CFLAGS += -DMALLOC_LEAK_CHECK
+endif
+
+LOCAL_MODULE:= libandroid_servers
+
+include $(BUILD_SHARED_LIBRARY)
+
+# =============================================================
+
+ifeq (,$(ONE_SHOT_MAKEFILE))
+# A full make is happening, so make everything.
+include $(call all-makefiles-under,$(LOCAL_PATH))
+else
+# If we ran an mm[m] command, we still want to build the individual
+# services that we depend on. This differs from the above condition
+# by only including service makefiles and not any tests or other
+# modules.
+include $(patsubst %,$(LOCAL_PATH)/%/Android.mk,$(services))
+endif
+
diff --git a/services/accessibility/Android.mk b/services/accessibility/Android.mk
new file mode 100644
index 0000000..d98fc28
--- /dev/null
+++ b/services/accessibility/Android.mk
@@ -0,0 +1,10 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := services.accessibility
+
+LOCAL_SRC_FILES += \
+      $(call all-java-files-under,java)
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/services/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
similarity index 100%
rename from services/java/com/android/server/accessibility/AccessibilityInputFilter.java
rename to services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
similarity index 100%
rename from services/java/com/android/server/accessibility/AccessibilityManagerService.java
rename to services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
diff --git a/services/java/com/android/server/accessibility/EventStreamTransformation.java b/services/accessibility/java/com/android/server/accessibility/EventStreamTransformation.java
similarity index 100%
rename from services/java/com/android/server/accessibility/EventStreamTransformation.java
rename to services/accessibility/java/com/android/server/accessibility/EventStreamTransformation.java
diff --git a/services/java/com/android/server/accessibility/GestureUtils.java b/services/accessibility/java/com/android/server/accessibility/GestureUtils.java
similarity index 100%
rename from services/java/com/android/server/accessibility/GestureUtils.java
rename to services/accessibility/java/com/android/server/accessibility/GestureUtils.java
diff --git a/services/java/com/android/server/accessibility/ScreenMagnifier.java b/services/accessibility/java/com/android/server/accessibility/ScreenMagnifier.java
similarity index 100%
rename from services/java/com/android/server/accessibility/ScreenMagnifier.java
rename to services/accessibility/java/com/android/server/accessibility/ScreenMagnifier.java
diff --git a/services/java/com/android/server/accessibility/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
similarity index 100%
rename from services/java/com/android/server/accessibility/TouchExplorer.java
rename to services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
diff --git a/services/appwidget/Android.mk b/services/appwidget/Android.mk
new file mode 100644
index 0000000..ca38f2f
--- /dev/null
+++ b/services/appwidget/Android.mk
@@ -0,0 +1,10 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := services.appwidget
+
+LOCAL_SRC_FILES += \
+      $(call all-java-files-under,java)
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetService.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetService.java
new file mode 100644
index 0000000..e208677
--- /dev/null
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetService.java
@@ -0,0 +1,384 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.appwidget;
+
+import android.app.ActivityManager;
+import android.appwidget.AppWidgetProviderInfo;
+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.os.Binder;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.widget.RemoteViews;
+
+import com.android.internal.appwidget.IAppWidgetHost;
+import com.android.internal.appwidget.IAppWidgetService;
+import com.android.internal.os.BackgroundThread;
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.SystemService;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.List;
+import java.util.Locale;
+
+
+/**
+ * SystemService that publishes an IAppWidgetService.
+ */
+public class AppWidgetService extends SystemService {
+
+    static final String TAG = "AppWidgetService";
+
+    final Context mContext;
+    final Handler mSaveStateHandler;
+
+    final SparseArray<AppWidgetServiceImpl> mAppWidgetServices;
+
+    public AppWidgetService(Context context) {
+        super(context);
+        mContext = context;
+
+        mSaveStateHandler = BackgroundThread.getHandler();
+
+        mAppWidgetServices = new SparseArray<AppWidgetServiceImpl>(5);
+        AppWidgetServiceImpl primary = new AppWidgetServiceImpl(context, 0, mSaveStateHandler);
+        mAppWidgetServices.append(0, primary);
+    }
+
+    @Override
+    public void onStart() {
+        publishBinderService(Context.APPWIDGET_SERVICE, mServiceImpl);
+    }
+
+    @Override
+    public void onBootPhase(int phase) {
+        if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
+            mServiceImpl.systemRunning(isSafeMode());
+        }
+    }
+
+    private final AppWidgetServiceStub mServiceImpl = new AppWidgetServiceStub();
+
+    private class AppWidgetServiceStub extends IAppWidgetService.Stub {
+
+        private boolean mSafeMode;
+        private Locale mLocale;
+        private PackageManager mPackageManager;
+
+        public void systemRunning(boolean safeMode) {
+            mSafeMode = safeMode;
+
+            mAppWidgetServices.get(0).systemReady(safeMode);
+
+            // Register for the boot completed broadcast, so we can send the
+            // ENABLE broacasts. If we try to send them now, they time out,
+            // because the system isn't ready to handle them yet.
+            mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL,
+                    new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null);
+
+            // Register for configuration changes so we can update the names
+            // of the widgets when the locale changes.
+            mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL,
+                    new IntentFilter(Intent.ACTION_CONFIGURATION_CHANGED), null, null);
+
+            // Register for broadcasts about package install, etc., so we can
+            // update the provider list.
+            IntentFilter filter = new IntentFilter();
+            filter.addAction(Intent.ACTION_PACKAGE_ADDED);
+            filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+            filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+            filter.addDataScheme("package");
+            mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL,
+                    filter, null, null);
+            // Register for events related to sdcard installation.
+            IntentFilter sdFilter = new IntentFilter();
+            sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
+            sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
+            mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL,
+                    sdFilter, null, null);
+
+            IntentFilter userFilter = new IntentFilter();
+            userFilter.addAction(Intent.ACTION_USER_REMOVED);
+            userFilter.addAction(Intent.ACTION_USER_STOPPING);
+            mContext.registerReceiver(new BroadcastReceiver() {
+                @Override
+                public void onReceive(Context context, Intent intent) {
+                    if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) {
+                        onUserRemoved(intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
+                                UserHandle.USER_NULL));
+                    } else if (Intent.ACTION_USER_STOPPING.equals(intent.getAction())) {
+                        onUserStopping(intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
+                                UserHandle.USER_NULL));
+                    }
+                }
+            }, userFilter);
+        }
+
+        @Override
+        public int allocateAppWidgetId(String packageName, int hostId, int userId)
+                throws RemoteException {
+            return getImplForUser(userId).allocateAppWidgetId(packageName, hostId);
+        }
+
+        @Override
+        public int[] getAppWidgetIdsForHost(int hostId, int userId) throws RemoteException {
+            return getImplForUser(userId).getAppWidgetIdsForHost(hostId);
+        }
+
+        @Override
+        public void deleteAppWidgetId(int appWidgetId, int userId) throws RemoteException {
+            getImplForUser(userId).deleteAppWidgetId(appWidgetId);
+        }
+
+        @Override
+        public void deleteHost(int hostId, int userId) throws RemoteException {
+            getImplForUser(userId).deleteHost(hostId);
+        }
+
+        @Override
+        public void deleteAllHosts(int userId) throws RemoteException {
+            getImplForUser(userId).deleteAllHosts();
+        }
+
+        @Override
+        public void bindAppWidgetId(int appWidgetId, ComponentName provider, Bundle options,
+                int userId) throws RemoteException {
+            getImplForUser(userId).bindAppWidgetId(appWidgetId, provider, options);
+        }
+
+        @Override
+        public boolean bindAppWidgetIdIfAllowed(
+                String packageName, int appWidgetId, ComponentName provider, Bundle options,
+                int userId) throws RemoteException {
+            return getImplForUser(userId).bindAppWidgetIdIfAllowed(
+                    packageName, appWidgetId, provider, options);
+        }
+
+        @Override
+        public boolean hasBindAppWidgetPermission(String packageName, int userId)
+                throws RemoteException {
+            return getImplForUser(userId).hasBindAppWidgetPermission(packageName);
+        }
+
+        @Override
+        public void setBindAppWidgetPermission(String packageName, boolean permission, int userId)
+                throws RemoteException {
+            getImplForUser(userId).setBindAppWidgetPermission(packageName, permission);
+        }
+
+        @Override
+        public void bindRemoteViewsService(int appWidgetId, Intent intent, IBinder connection,
+                int userId) throws RemoteException {
+            getImplForUser(userId).bindRemoteViewsService(appWidgetId, intent, connection);
+        }
+
+        @Override
+        public int[] startListening(IAppWidgetHost host, String packageName, int hostId,
+                List<RemoteViews> updatedViews, int userId) throws RemoteException {
+            return getImplForUser(userId).startListening(host, packageName, hostId, updatedViews);
+        }
+
+        public void onUserRemoved(int userId) {
+            if (userId < 1) return;
+            synchronized (mAppWidgetServices) {
+                AppWidgetServiceImpl impl = mAppWidgetServices.get(userId);
+                mAppWidgetServices.remove(userId);
+
+                if (impl == null) {
+                    AppWidgetServiceImpl.getSettingsFile(userId).delete();
+                } else {
+                    impl.onUserRemoved();
+                }
+            }
+        }
+
+        public void onUserStopping(int userId) {
+            if (userId < 1) return;
+            synchronized (mAppWidgetServices) {
+                AppWidgetServiceImpl impl = mAppWidgetServices.get(userId);
+                if (impl != null) {
+                    mAppWidgetServices.remove(userId);
+                    impl.onUserStopping();
+                }
+            }
+        }
+
+        private void checkPermission(int userId) {
+            int realUserId = ActivityManager.handleIncomingUser(
+                    Binder.getCallingPid(),
+                    Binder.getCallingUid(),
+                    userId,
+                    false, /* allowAll */
+                    true, /* requireFull */
+                    this.getClass().getSimpleName(),
+                    this.getClass().getPackage().getName());
+        }
+
+        private AppWidgetServiceImpl getImplForUser(int userId) {
+            checkPermission(userId);
+            boolean sendInitial = false;
+            AppWidgetServiceImpl service;
+            synchronized (mAppWidgetServices) {
+                service = mAppWidgetServices.get(userId);
+                if (service == null) {
+                    Slog.i(TAG, "Unable to find AppWidgetServiceImpl for user " + userId
+                            + ", adding");
+                    // TODO: Verify that it's a valid user
+                    service = new AppWidgetServiceImpl(mContext, userId, mSaveStateHandler);
+                    service.systemReady(mSafeMode);
+                    // Assume that BOOT_COMPLETED was received, as this is a non-primary user.
+                    mAppWidgetServices.append(userId, service);
+                    sendInitial = true;
+                }
+            }
+            if (sendInitial) {
+                service.sendInitialBroadcasts();
+            }
+            return service;
+        }
+
+        @Override
+        public int[] getAppWidgetIds(ComponentName provider, int userId) throws RemoteException {
+            return getImplForUser(userId).getAppWidgetIds(provider);
+        }
+
+        @Override
+        public AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId, int userId)
+                throws RemoteException {
+            return getImplForUser(userId).getAppWidgetInfo(appWidgetId);
+        }
+
+        @Override
+        public RemoteViews getAppWidgetViews(int appWidgetId, int userId) throws RemoteException {
+            return getImplForUser(userId).getAppWidgetViews(appWidgetId);
+        }
+
+        @Override
+        public void updateAppWidgetOptions(int appWidgetId, Bundle options, int userId) {
+            getImplForUser(userId).updateAppWidgetOptions(appWidgetId, options);
+        }
+
+        @Override
+        public Bundle getAppWidgetOptions(int appWidgetId, int userId) {
+            return getImplForUser(userId).getAppWidgetOptions(appWidgetId);
+        }
+
+        @Override
+        public List<AppWidgetProviderInfo> getInstalledProviders(int categoryFilter, int userId)
+                throws RemoteException {
+            return getImplForUser(userId).getInstalledProviders(categoryFilter);
+        }
+
+        @Override
+        public void notifyAppWidgetViewDataChanged(int[] appWidgetIds, int viewId, int userId)
+                throws RemoteException {
+            getImplForUser(userId).notifyAppWidgetViewDataChanged(
+                    appWidgetIds, viewId);
+        }
+
+        @Override
+        public void partiallyUpdateAppWidgetIds(int[] appWidgetIds, RemoteViews views, int userId)
+                throws RemoteException {
+            getImplForUser(userId).partiallyUpdateAppWidgetIds(
+                    appWidgetIds, views);
+        }
+
+        @Override
+        public void stopListening(int hostId, int userId) throws RemoteException {
+            getImplForUser(userId).stopListening(hostId);
+        }
+
+        @Override
+        public void unbindRemoteViewsService(int appWidgetId, Intent intent, int userId)
+                throws RemoteException {
+            getImplForUser(userId).unbindRemoteViewsService(
+                    appWidgetId, intent);
+        }
+
+        @Override
+        public void updateAppWidgetIds(int[] appWidgetIds, RemoteViews views, int userId)
+                throws RemoteException {
+            getImplForUser(userId).updateAppWidgetIds(appWidgetIds, views);
+        }
+
+        @Override
+        public void updateAppWidgetProvider(ComponentName provider, RemoteViews views, int userId)
+                throws RemoteException {
+            getImplForUser(userId).updateAppWidgetProvider(provider, views);
+        }
+
+        @Override
+        public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+            mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
+
+            // Dump the state of all the app widget providers
+            synchronized (mAppWidgetServices) {
+                IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ");
+                for (int i = 0; i < mAppWidgetServices.size(); i++) {
+                    pw.println("User: " + mAppWidgetServices.keyAt(i));
+                    ipw.increaseIndent();
+                    AppWidgetServiceImpl service = mAppWidgetServices.valueAt(i);
+                    service.dump(fd, ipw, args);
+                    ipw.decreaseIndent();
+                }
+            }
+        }
+
+        BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+            public void onReceive(Context context, Intent intent) {
+                String action = intent.getAction();
+                // Slog.d(TAG, "received " + action);
+                if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
+                    int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
+                    if (userId >= 0) {
+                        getImplForUser(userId).sendInitialBroadcasts();
+                    } else {
+                        Slog.w(TAG, "Incorrect user handle supplied in " + intent);
+                    }
+                } else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
+                    for (int i = 0; i < mAppWidgetServices.size(); i++) {
+                        AppWidgetServiceImpl service = mAppWidgetServices.valueAt(i);
+                        service.onConfigurationChanged();
+                    }
+                } else {
+                    int sendingUser = getSendingUserId();
+                    if (sendingUser == UserHandle.USER_ALL) {
+                        for (int i = 0; i < mAppWidgetServices.size(); i++) {
+                            AppWidgetServiceImpl service = mAppWidgetServices.valueAt(i);
+                            service.onBroadcastReceived(intent);
+                        }
+                    } else {
+                        AppWidgetServiceImpl service = mAppWidgetServices.get(sendingUser);
+                        if (service != null) {
+                            service.onBroadcastReceived(intent);
+                        }
+                    }
+                }
+            }
+        };
+    }
+}
diff --git a/services/java/com/android/server/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
similarity index 99%
rename from services/java/com/android/server/AppWidgetServiceImpl.java
rename to services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 69ae846..98dead3 100644
--- a/services/java/com/android/server/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server;
+package com.android.server.appwidget;
 
 import android.app.AlarmManager;
 import android.app.AppGlobals;
diff --git a/services/backup/Android.mk b/services/backup/Android.mk
new file mode 100644
index 0000000..3e686d1
--- /dev/null
+++ b/services/backup/Android.mk
@@ -0,0 +1,12 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := services.backup
+
+LOCAL_SRC_FILES += \
+      $(call all-java-files-under,java)
+
+LOCAL_JAVA_LIBRARIES := services.core
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
similarity index 99%
rename from services/java/com/android/server/BackupManagerService.java
rename to services/backup/java/com/android/server/backup/BackupManagerService.java
index 6d65a70..b3571d7 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server;
+package com.android.server.backup;
 
 import android.app.ActivityManagerNative;
 import android.app.AlarmManager;
@@ -83,7 +83,8 @@
 import com.android.internal.backup.IBackupTransport;
 import com.android.internal.backup.IObbBackupService;
 import com.android.server.EventLogTags;
-import com.android.server.PackageManagerBackupAgent.Metadata;
+import com.android.server.SystemService;
+import com.android.server.backup.PackageManagerBackupAgent.Metadata;
 
 import java.io.BufferedInputStream;
 import java.io.BufferedOutputStream;
@@ -135,7 +136,8 @@
 import javax.crypto.spec.PBEKeySpec;
 import javax.crypto.spec.SecretKeySpec;
 
-class BackupManagerService extends IBackupManager.Stub {
+public class BackupManagerService extends IBackupManager.Stub {
+
     private static final String TAG = "BackupManagerService";
     private static final boolean DEBUG = true;
     private static final boolean MORE_DEBUG = false;
@@ -276,6 +278,20 @@
     // Watch the device provisioning operation during setup
     ContentObserver mProvisionedObserver;
 
+    public static final class Lifecycle extends SystemService {
+        private final BackupManagerService mService;
+
+        public Lifecycle(Context context) {
+            super(context);
+            mService = new BackupManagerService(context);
+        }
+
+        @Override
+        public void onStart() {
+            publishBinderService(Context.BACKUP_SERVICE, mService);
+        }
+    }
+
     class ProvisionedObserver extends ContentObserver {
         public ProvisionedObserver(Handler handler) {
             super(handler);
@@ -1206,7 +1222,8 @@
         // First, on an encrypted device we require matching the device pw
         final boolean isEncrypted;
         try {
-            isEncrypted = (mMountService.getEncryptionState() != MountService.ENCRYPTION_STATE_NONE);
+            isEncrypted = (mMountService.getEncryptionState() !=
+                    IMountService.ENCRYPTION_STATE_NONE);
             if (isEncrypted) {
                 if (DEBUG) {
                     Slog.i(TAG, "Device encrypted; verifying against device data pw");
@@ -5523,7 +5540,8 @@
 
                         boolean isEncrypted;
                         try {
-                            isEncrypted = (mMountService.getEncryptionState() != MountService.ENCRYPTION_STATE_NONE);
+                            isEncrypted = (mMountService.getEncryptionState() !=
+                                    IMountService.ENCRYPTION_STATE_NONE);
                             if (isEncrypted) Slog.w(TAG, "Device is encrypted; forcing enc password");
                         } catch (RemoteException e) {
                             // couldn't contact the mount service; fail "safe" and assume encryption
@@ -6181,7 +6199,7 @@
                     }
                 }
 
-                // clean up the BackupManagerService side of the bookkeeping
+                // clean up the BackupManagerImpl side of the bookkeeping
                 // and cancel any pending timeout message
                 mBackupManager.clearRestoreSession(mSession);
             }
diff --git a/services/java/com/android/server/PackageManagerBackupAgent.java b/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java
similarity index 99%
rename from services/java/com/android/server/PackageManagerBackupAgent.java
rename to services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java
index 77bddb0..495da88 100644
--- a/services/java/com/android/server/PackageManagerBackupAgent.java
+++ b/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server;
+package com.android.server.backup;
 
 import android.app.backup.BackupAgent;
 import android.app.backup.BackupDataInput;
diff --git a/services/java/com/android/server/SystemBackupAgent.java b/services/backup/java/com/android/server/backup/SystemBackupAgent.java
similarity index 79%
rename from services/java/com/android/server/SystemBackupAgent.java
rename to services/backup/java/com/android/server/backup/SystemBackupAgent.java
index 8cf273d..26e2e2a 100644
--- a/services/java/com/android/server/SystemBackupAgent.java
+++ b/services/backup/java/com/android/server/backup/SystemBackupAgent.java
@@ -14,9 +14,10 @@
  * limitations under the License.
  */
 
-package com.android.server;
+package com.android.server.backup;
 
 
+import android.app.IWallpaperManager;
 import android.app.backup.BackupDataInput;
 import android.app.backup.BackupDataOutput;
 import android.app.backup.BackupAgentHelper;
@@ -26,11 +27,11 @@
 import android.content.Context;
 import android.os.Environment;
 import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.UserHandle;
 import android.util.Slog;
 
-
 import java.io.File;
 import java.io.IOException;
 
@@ -63,16 +64,23 @@
     public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
             ParcelFileDescriptor newState) throws IOException {
         // We only back up the data under the current "wallpaper" schema with metadata
-        WallpaperManagerService wallpaper = (WallpaperManagerService)ServiceManager.getService(
+        IWallpaperManager wallpaper = (IWallpaperManager)ServiceManager.getService(
                 Context.WALLPAPER_SERVICE);
         String[] files = new String[] { WALLPAPER_IMAGE, WALLPAPER_INFO };
         String[] keys = new String[] { WALLPAPER_IMAGE_KEY, WALLPAPER_INFO_KEY };
-        if (wallpaper != null && wallpaper.getName() != null && wallpaper.getName().length() > 0) {
-            // When the wallpaper has a name, back up the info by itself.
-            // TODO: Don't rely on the innards of the service object like this!
-            // TODO: Send a delete for any stored wallpaper image in this case?
-            files = new String[] { WALLPAPER_INFO };
-            keys = new String[] { WALLPAPER_INFO_KEY };
+        if (wallpaper != null) {
+            try {
+                final String wallpaperName = wallpaper.getName();
+                if (wallpaperName != null && wallpaperName.length() > 0) {
+                    // When the wallpaper has a name, back up the info by itself.
+                    // TODO: Don't rely on the innards of the service object like this!
+                    // TODO: Send a delete for any stored wallpaper image in this case?
+                    files = new String[] { WALLPAPER_INFO };
+                    keys = new String[] { WALLPAPER_INFO_KEY };
+                }
+            } catch (RemoteException re) {
+                Slog.e(TAG, "Couldn't get wallpaper name\n" + re);
+            }
         }
         addHelper("wallpaper", new WallpaperBackupHelper(SystemBackupAgent.this, files, keys));
         super.onBackup(oldState, data, newState);
@@ -109,9 +117,15 @@
         try {
             super.onRestore(data, appVersionCode, newState);
 
-            WallpaperManagerService wallpaper = (WallpaperManagerService)ServiceManager.getService(
+            IWallpaperManager wallpaper = (IWallpaperManager) ServiceManager.getService(
                     Context.WALLPAPER_SERVICE);
-            wallpaper.settingsRestored();
+            if (wallpaper != null) {
+                try {
+                    wallpaper.settingsRestored();
+                } catch (RemoteException re) {
+                    Slog.e(TAG, "Couldn't restore settings\n" + re);
+                }
+            }
         } catch (IOException ex) {
             // If there was a failure, delete everything for the wallpaper, this is too aggressive,
             // but this is hopefully a rare failure.
@@ -149,10 +163,16 @@
             FullBackup.restoreFile(data, size, type, mode, mtime, outFile);
 
             if (restoredWallpaper) {
-                WallpaperManagerService wallpaper =
-                        (WallpaperManagerService)ServiceManager.getService(
+                IWallpaperManager wallpaper =
+                        (IWallpaperManager)ServiceManager.getService(
                         Context.WALLPAPER_SERVICE);
-                wallpaper.settingsRestored();
+                if (wallpaper != null) {
+                    try {
+                        wallpaper.settingsRestored();
+                    } catch (RemoteException re) {
+                        Slog.e(TAG, "Couldn't restore settings\n" + re);
+                    }
+                }
             }
         } catch (IOException e) {
             if (restoredWallpaper) {
diff --git a/services/core/Android.mk b/services/core/Android.mk
new file mode 100644
index 0000000..5c45201
--- /dev/null
+++ b/services/core/Android.mk
@@ -0,0 +1,14 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := services.core
+
+LOCAL_SRC_FILES += \
+    $(call all-java-files-under,java) \
+    java/com/android/server/EventLogTags.logtags \
+    java/com/android/server/am/EventLogTags.logtags
+
+LOCAL_JAVA_LIBRARIES := android.policy telephony-common
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/services/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
similarity index 88%
rename from services/java/com/android/server/AlarmManagerService.java
rename to services/core/java/com/android/server/AlarmManagerService.java
index defc6ef..c14ed8b 100644
--- a/services/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -31,6 +31,7 @@
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Handler;
+import android.os.IBinder;
 import android.os.Message;
 import android.os.PowerManager;
 import android.os.SystemClock;
@@ -64,54 +65,51 @@
 
 import com.android.internal.util.LocalLog;
 
-class AlarmManagerService extends IAlarmManager.Stub {
+class AlarmManagerService extends SystemService {
     // The threshold for how long an alarm can be late before we print a
     // warning message.  The time duration is in milliseconds.
     private static final long LATE_ALARM_THRESHOLD = 10 * 1000;
 
     private static final int RTC_WAKEUP_MASK = 1 << RTC_WAKEUP;
     private static final int RTC_MASK = 1 << RTC;
-    private static final int ELAPSED_REALTIME_WAKEUP_MASK = 1 << ELAPSED_REALTIME_WAKEUP; 
+    private static final int ELAPSED_REALTIME_WAKEUP_MASK = 1 << ELAPSED_REALTIME_WAKEUP;
     private static final int ELAPSED_REALTIME_MASK = 1 << ELAPSED_REALTIME;
-    private static final int TIME_CHANGED_MASK = 1 << 16;
-    private static final int IS_WAKEUP_MASK = RTC_WAKEUP_MASK|ELAPSED_REALTIME_WAKEUP_MASK;
+    static final int TIME_CHANGED_MASK = 1 << 16;
+    static final int IS_WAKEUP_MASK = RTC_WAKEUP_MASK|ELAPSED_REALTIME_WAKEUP_MASK;
 
     // Mask for testing whether a given alarm type is wakeup vs non-wakeup
-    private static final int TYPE_NONWAKEUP_MASK = 0x1; // low bit => non-wakeup
+    static final int TYPE_NONWAKEUP_MASK = 0x1; // low bit => non-wakeup
 
-    private static final String TAG = "AlarmManager";
-    private static final String ClockReceiver_TAG = "ClockReceiver";
-    private static final boolean localLOGV = false;
-    private static final boolean DEBUG_BATCH = localLOGV || false;
-    private static final boolean DEBUG_VALIDATE = localLOGV || false;
-    private static final int ALARM_EVENT = 1;
-    private static final String TIMEZONE_PROPERTY = "persist.sys.timezone";
+    static final String TAG = "AlarmManager";
+    static final String ClockReceiver_TAG = "ClockReceiver";
+    static final boolean localLOGV = false;
+    static final boolean DEBUG_BATCH = localLOGV || false;
+    static final boolean DEBUG_VALIDATE = localLOGV || false;
+    static final int ALARM_EVENT = 1;
+    static final String TIMEZONE_PROPERTY = "persist.sys.timezone";
     
-    private static final Intent mBackgroundIntent
+    static final Intent mBackgroundIntent
             = new Intent().addFlags(Intent.FLAG_FROM_BACKGROUND);
-    private static final IncreasingTimeOrder sIncreasingTimeOrder = new IncreasingTimeOrder();
+    static final IncreasingTimeOrder sIncreasingTimeOrder = new IncreasingTimeOrder();
     
-    private static final boolean WAKEUP_STATS = false;
+    static final boolean WAKEUP_STATS = false;
 
-    private final Context mContext;
+    final LocalLog mLog = new LocalLog(TAG);
 
-    private final LocalLog mLog = new LocalLog(TAG);
+    final Object mLock = new Object();
 
-    private Object mLock = new Object();
-
-    private long mNativeData;
+    long mNativeData;
     private long mNextWakeup;
     private long mNextNonWakeup;
-    private int mBroadcastRefCount = 0;
-    private PowerManager.WakeLock mWakeLock;
-    private ArrayList<InFlight> mInFlight = new ArrayList<InFlight>();
-    private final AlarmThread mWaitThread = new AlarmThread();
-    private final AlarmHandler mHandler = new AlarmHandler();
-    private ClockReceiver mClockReceiver;
+    int mBroadcastRefCount = 0;
+    PowerManager.WakeLock mWakeLock;
+    ArrayList<InFlight> mInFlight = new ArrayList<InFlight>();
+    final AlarmHandler mHandler = new AlarmHandler();
+    ClockReceiver mClockReceiver;
     private UninstallReceiver mUninstallReceiver;
-    private final ResultReceiver mResultReceiver = new ResultReceiver();
-    private final PendingIntent mTimeTickSender;
-    private final PendingIntent mDateChangeSender;
+    final ResultReceiver mResultReceiver = new ResultReceiver();
+    PendingIntent mTimeTickSender;
+    PendingIntent mDateChangeSender;
 
     class WakeupEvent {
         public long when;
@@ -125,8 +123,8 @@
         }
     }
 
-    private final LinkedList<WakeupEvent> mRecentWakeups = new LinkedList<WakeupEvent>();
-    private final long RECENT_WAKEUP_PERIOD = 1000L * 60 * 60 * 24; // one day
+    final LinkedList<WakeupEvent> mRecentWakeups = new LinkedList<WakeupEvent>();
+    final long RECENT_WAKEUP_PERIOD = 1000L * 60 * 60 * 24; // one day
 
     static final class Batch {
         long start;     // These endpoints are always in ELAPSED
@@ -317,9 +315,13 @@
     }
     
     // minimum recurrence period or alarm futurity for us to be able to fuzz it
-    private static final long MIN_FUZZABLE_INTERVAL = 10000;
-    private static final BatchTimeOrder sBatchOrder = new BatchTimeOrder();
-    private final ArrayList<Batch> mAlarmBatches = new ArrayList<Batch>();
+    static final long MIN_FUZZABLE_INTERVAL = 10000;
+    static final BatchTimeOrder sBatchOrder = new BatchTimeOrder();
+    final ArrayList<Batch> mAlarmBatches = new ArrayList<Batch>();
+
+    public AlarmManagerService(Context context) {
+        super(context);
+    }
 
     static long convertToElapsed(long when, int type) {
         final boolean isRtc = (type == RTC || type == RTC_WAKEUP);
@@ -403,7 +405,7 @@
         }
     }
 
-    private static final class InFlight extends Intent {
+    static final class InFlight extends Intent {
         final PendingIntent mPendingIntent;
         final WorkSource mWorkSource;
         final Pair<String, ComponentName> mTarget;
@@ -427,7 +429,7 @@
         }
     }
 
-    private static final class FilterStats {
+    static final class FilterStats {
         final BroadcastStats mBroadcastStats;
         final Pair<String, ComponentName> mTarget;
 
@@ -443,7 +445,7 @@
         }
     }
     
-    private static final class BroadcastStats {
+    static final class BroadcastStats {
         final String mPackageName;
 
         long aggregateTime;
@@ -459,47 +461,48 @@
         }
     }
     
-    private final HashMap<String, BroadcastStats> mBroadcastStats
+    final HashMap<String, BroadcastStats> mBroadcastStats
             = new HashMap<String, BroadcastStats>();
     
-    public AlarmManagerService(Context context) {
-        mContext = context;
+    @Override
+    public void onStart() {
         mNativeData = init();
         mNextWakeup = mNextNonWakeup = 0;
 
         // We have to set current TimeZone info to kernel
         // because kernel doesn't keep this after reboot
-        String tz = SystemProperties.get(TIMEZONE_PROPERTY);
-        if (tz != null) {
-            setTimeZone(tz);
-        }
+        setTimeZoneImpl(SystemProperties.get(TIMEZONE_PROPERTY));
 
-        PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
+        PowerManager pm = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE);
         mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
         
-        mTimeTickSender = PendingIntent.getBroadcastAsUser(context, 0,
+        mTimeTickSender = PendingIntent.getBroadcastAsUser(getContext(), 0,
                 new Intent(Intent.ACTION_TIME_TICK).addFlags(
                         Intent.FLAG_RECEIVER_REGISTERED_ONLY
                         | Intent.FLAG_RECEIVER_FOREGROUND), 0,
                         UserHandle.ALL);
         Intent intent = new Intent(Intent.ACTION_DATE_CHANGED);
         intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
-        mDateChangeSender = PendingIntent.getBroadcastAsUser(context, 0, intent,
+        mDateChangeSender = PendingIntent.getBroadcastAsUser(getContext(), 0, intent,
                 Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT, UserHandle.ALL);
         
         // now that we have initied the driver schedule the alarm
-        mClockReceiver= new ClockReceiver();
+        mClockReceiver = new ClockReceiver();
         mClockReceiver.scheduleTimeTickEvent();
         mClockReceiver.scheduleDateChangedEvent();
         mUninstallReceiver = new UninstallReceiver();
         
         if (mNativeData != 0) {
-            mWaitThread.start();
+            AlarmThread waitThread = new AlarmThread();
+            waitThread.start();
         } else {
             Slog.w(TAG, "Failed to open alarm driver. Falling back to a handler.");
         }
+
+        publishBinderService(Context.ALARM_SERVICE, mService);
     }
-    
+
+    @Override
     protected void finalize() throws Throwable {
         try {
             close(mNativeData);
@@ -508,19 +511,51 @@
         }
     }
 
-    @Override
-    public void set(int type, long triggerAtTime, long windowLength, long interval,
-            PendingIntent operation, WorkSource workSource) {
-        if (workSource != null) {
-            mContext.enforceCallingPermission(
-                    android.Manifest.permission.UPDATE_DEVICE_STATS,
-                    "AlarmManager.set");
+    void setTimeZoneImpl(String tz) {
+        if (TextUtils.isEmpty(tz)) {
+            return;
         }
 
-        set(type, triggerAtTime, windowLength, interval, operation, false, workSource);
+        TimeZone zone = TimeZone.getTimeZone(tz);
+        // Prevent reentrant calls from stepping on each other when writing
+        // the time zone property
+        boolean timeZoneWasChanged = false;
+        synchronized (this) {
+            String current = SystemProperties.get(TIMEZONE_PROPERTY);
+            if (current == null || !current.equals(zone.getID())) {
+                if (localLOGV) {
+                    Slog.v(TAG, "timezone changed: " + current + ", new=" + zone.getID());
+                }
+                timeZoneWasChanged = true;
+                SystemProperties.set(TIMEZONE_PROPERTY, zone.getID());
+            }
+
+            // Update the kernel timezone information
+            // Kernel tracks time offsets as 'minutes west of GMT'
+            int gmtOffset = zone.getOffset(System.currentTimeMillis());
+            setKernelTimezone(mNativeData, -(gmtOffset / 60000));
+        }
+
+        TimeZone.setDefault(null);
+
+        if (timeZoneWasChanged) {
+            Intent intent = new Intent(Intent.ACTION_TIMEZONE_CHANGED);
+            intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
+            intent.putExtra("time-zone", zone.getID());
+            getContext().sendBroadcastAsUser(intent, UserHandle.ALL);
+        }
     }
 
-    public void set(int type, long triggerAtTime, long windowLength, long interval,
+    void removeImpl(PendingIntent operation) {
+        if (operation == null) {
+            return;
+        }
+        synchronized (mLock) {
+            removeLocked(operation);
+        }
+    }
+
+    void setImpl(int type, long triggerAtTime, long windowLength, long interval,
             PendingIntent operation, boolean isStandalone, WorkSource workSource) {
         if (operation == null) {
             Slog.w(TAG, "set/setRepeating ignored because there is no intent");
@@ -606,238 +641,71 @@
         rescheduleKernelAlarmsLocked();
     }
 
-    private void logBatchesLocked() {
-        ByteArrayOutputStream bs = new ByteArrayOutputStream(2048);
-        PrintWriter pw = new PrintWriter(bs);
-        final long nowRTC = System.currentTimeMillis();
-        final long nowELAPSED = SystemClock.elapsedRealtime();
-        final int NZ = mAlarmBatches.size();
-        for (int iz = 0; iz < NZ; iz++) {
-            Batch bz = mAlarmBatches.get(iz);
-            pw.append("Batch "); pw.print(iz); pw.append(": "); pw.println(bz);
-            dumpAlarmList(pw, bz.alarms, "  ", nowELAPSED, nowRTC);
-            pw.flush();
-            Slog.v(TAG, bs.toString());
-            bs.reset();
-        }
-    }
-
-    private boolean validateConsistencyLocked() {
-        if (DEBUG_VALIDATE) {
-            long lastTime = Long.MIN_VALUE;
-            final int N = mAlarmBatches.size();
-            for (int i = 0; i < N; i++) {
-                Batch b = mAlarmBatches.get(i);
-                if (b.start >= lastTime) {
-                    // duplicate start times are okay because of standalone batches
-                    lastTime = b.start;
-                } else {
-                    Slog.e(TAG, "CONSISTENCY FAILURE: Batch " + i + " is out of order");
-                    logBatchesLocked();
-                    return false;
-                }
-            }
-        }
-        return true;
-    }
-
-    private Batch findFirstWakeupBatchLocked() {
-        final int N = mAlarmBatches.size();
-        for (int i = 0; i < N; i++) {
-            Batch b = mAlarmBatches.get(i);
-            if (b.hasWakeups()) {
-                return b;
-            }
-        }
-        return null;
-    }
-
-    private void rescheduleKernelAlarmsLocked() {
-        // Schedule the next upcoming wakeup alarm.  If there is a deliverable batch
-        // prior to that which contains no wakeups, we schedule that as well.
-        if (mAlarmBatches.size() > 0) {
-            final Batch firstWakeup = findFirstWakeupBatchLocked();
-            final Batch firstBatch = mAlarmBatches.get(0);
-            if (firstWakeup != null && mNextWakeup != firstWakeup.start) {
-                mNextWakeup = firstWakeup.start;
-                setLocked(ELAPSED_REALTIME_WAKEUP, firstWakeup.start);
-            }
-            if (firstBatch != firstWakeup && mNextNonWakeup != firstBatch.start) {
-                mNextNonWakeup = firstBatch.start;
-                setLocked(ELAPSED_REALTIME, firstBatch.start);
-            }
-        }
-    }
-
-    public boolean setTime(long millis) {
-        mContext.enforceCallingOrSelfPermission(
-                "android.permission.SET_TIME",
-                "setTime");
-
-        if (mNativeData == 0) {
-            Slog.w(TAG, "Not setting time since no alarm driver is available.");
-            return false;
-        }
-
-        synchronized (mLock) {
-            return setKernelTime(mNativeData, millis) == 0;
-        }
-    }
-
-    public void setTimeZone(String tz) {
-        mContext.enforceCallingOrSelfPermission(
-                "android.permission.SET_TIME_ZONE",
-                "setTimeZone");
-
-        long oldId = Binder.clearCallingIdentity();
-        try {
-            if (TextUtils.isEmpty(tz)) return;
-            TimeZone zone = TimeZone.getTimeZone(tz);
-            // Prevent reentrant calls from stepping on each other when writing
-            // the time zone property
-            boolean timeZoneWasChanged = false;
-            synchronized (this) {
-                String current = SystemProperties.get(TIMEZONE_PROPERTY);
-                if (current == null || !current.equals(zone.getID())) {
-                    if (localLOGV) {
-                        Slog.v(TAG, "timezone changed: " + current + ", new=" + zone.getID());
-                    }
-                    timeZoneWasChanged = true;
-                    SystemProperties.set(TIMEZONE_PROPERTY, zone.getID());
-                }
-
-                // Update the kernel timezone information
-                // Kernel tracks time offsets as 'minutes west of GMT'
-                int gmtOffset = zone.getOffset(System.currentTimeMillis());
-                setKernelTimezone(mNativeData, -(gmtOffset / 60000));
+    private final IBinder mService = new IAlarmManager.Stub() {
+        @Override
+        public void set(int type, long triggerAtTime, long windowLength, long interval,
+                PendingIntent operation, WorkSource workSource) {
+            if (workSource != null) {
+                getContext().enforceCallingPermission(
+                        android.Manifest.permission.UPDATE_DEVICE_STATS,
+                        "AlarmManager.set");
             }
 
-            TimeZone.setDefault(null);
+            setImpl(type, triggerAtTime, windowLength, interval, operation,
+                    false, workSource);
+        }
 
-            if (timeZoneWasChanged) {
-                Intent intent = new Intent(Intent.ACTION_TIMEZONE_CHANGED);
-                intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
-                intent.putExtra("time-zone", zone.getID());
-                mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
+        @Override
+        public boolean setTime(long millis) {
+            getContext().enforceCallingOrSelfPermission(
+                    "android.permission.SET_TIME",
+                    "setTime");
+
+            if (mNativeData == 0) {
+                Slog.w(TAG, "Not setting time since no alarm driver is available.");
+                return false;
             }
-        } finally {
-            Binder.restoreCallingIdentity(oldId);
-        }
-    }
-    
-    public void remove(PendingIntent operation) {
-        if (operation == null) {
-            return;
-        }
-        synchronized (mLock) {
-            removeLocked(operation);
-        }
-    }
-    
-    public void removeLocked(PendingIntent operation) {
-        boolean didRemove = false;
-        for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
-            Batch b = mAlarmBatches.get(i);
-            didRemove |= b.remove(operation);
-            if (b.size() == 0) {
-                mAlarmBatches.remove(i);
+
+            synchronized (mLock) {
+                return setKernelTime(mNativeData, millis) == 0;
             }
         }
 
-        if (didRemove) {
-            if (DEBUG_BATCH) {
-                Slog.v(TAG, "remove(operation) changed bounds; rebatching");
-            }
-            rebatchAllAlarmsLocked(true);
-            rescheduleKernelAlarmsLocked();
-        }
-    }
+        @Override
+        public void setTimeZone(String tz) {
+            getContext().enforceCallingOrSelfPermission(
+                    "android.permission.SET_TIME_ZONE",
+                    "setTimeZone");
 
-    public void removeLocked(String packageName) {
-        boolean didRemove = false;
-        for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
-            Batch b = mAlarmBatches.get(i);
-            didRemove |= b.remove(packageName);
-            if (b.size() == 0) {
-                mAlarmBatches.remove(i);
+            final long oldId = Binder.clearCallingIdentity();
+            try {
+                setTimeZoneImpl(tz);
+            } finally {
+                Binder.restoreCallingIdentity(oldId);
             }
         }
 
-        if (didRemove) {
-            if (DEBUG_BATCH) {
-                Slog.v(TAG, "remove(package) changed bounds; rebatching");
-            }
-            rebatchAllAlarmsLocked(true);
-            rescheduleKernelAlarmsLocked();
-        }
-    }
+        @Override
+        public void remove(PendingIntent operation) {
+            removeImpl(operation);
 
-    public void removeUserLocked(int userHandle) {
-        boolean didRemove = false;
-        for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
-            Batch b = mAlarmBatches.get(i);
-            didRemove |= b.remove(userHandle);
-            if (b.size() == 0) {
-                mAlarmBatches.remove(i);
-            }
         }
 
-        if (didRemove) {
-            if (DEBUG_BATCH) {
-                Slog.v(TAG, "remove(user) changed bounds; rebatching");
+        @Override
+        protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+            if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+                    != PackageManager.PERMISSION_GRANTED) {
+                pw.println("Permission Denial: can't dump AlarmManager from from pid="
+                        + Binder.getCallingPid()
+                        + ", uid=" + Binder.getCallingUid());
+                return;
             }
-            rebatchAllAlarmsLocked(true);
-            rescheduleKernelAlarmsLocked();
-        }
-    }
 
-    public boolean lookForPackageLocked(String packageName) {
-        for (int i = 0; i < mAlarmBatches.size(); i++) {
-            Batch b = mAlarmBatches.get(i);
-            if (b.hasPackage(packageName)) {
-                return true;
-            }
+            dumpImpl(pw);
         }
-        return false;
-    }
+    };
 
-    private void setLocked(int type, long when)
-    {
-        if (mNativeData != 0)
-        {
-            // The kernel never triggers alarms with negative wakeup times
-            // so we ensure they are positive.
-            long alarmSeconds, alarmNanoseconds;
-            if (when < 0) {
-                alarmSeconds = 0;
-                alarmNanoseconds = 0;
-            } else {
-                alarmSeconds = when / 1000;
-                alarmNanoseconds = (when % 1000) * 1000 * 1000;
-            }
-            
-            set(mNativeData, type, alarmSeconds, alarmNanoseconds);
-        }
-        else
-        {
-            Message msg = Message.obtain();
-            msg.what = ALARM_EVENT;
-            
-            mHandler.removeMessages(ALARM_EVENT);
-            mHandler.sendMessageAtTime(msg, when);
-        }
-    }
-    
-    @Override
-    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
-                != PackageManager.PERMISSION_GRANTED) {
-            pw.println("Permission Denial: can't dump AlarmManager from from pid="
-                    + Binder.getCallingPid()
-                    + ", uid=" + Binder.getCallingUid());
-            return;
-        }
-        
+    void dumpImpl(PrintWriter pw) {
         synchronized (mLock) {
             pw.println("Current Alarm Manager state:");
             final long nowRTC = System.currentTimeMillis();
@@ -987,6 +855,159 @@
         }
     }
 
+    private void logBatchesLocked() {
+        ByteArrayOutputStream bs = new ByteArrayOutputStream(2048);
+        PrintWriter pw = new PrintWriter(bs);
+        final long nowRTC = System.currentTimeMillis();
+        final long nowELAPSED = SystemClock.elapsedRealtime();
+        final int NZ = mAlarmBatches.size();
+        for (int iz = 0; iz < NZ; iz++) {
+            Batch bz = mAlarmBatches.get(iz);
+            pw.append("Batch "); pw.print(iz); pw.append(": "); pw.println(bz);
+            dumpAlarmList(pw, bz.alarms, "  ", nowELAPSED, nowRTC);
+            pw.flush();
+            Slog.v(TAG, bs.toString());
+            bs.reset();
+        }
+    }
+
+    private boolean validateConsistencyLocked() {
+        if (DEBUG_VALIDATE) {
+            long lastTime = Long.MIN_VALUE;
+            final int N = mAlarmBatches.size();
+            for (int i = 0; i < N; i++) {
+                Batch b = mAlarmBatches.get(i);
+                if (b.start >= lastTime) {
+                    // duplicate start times are okay because of standalone batches
+                    lastTime = b.start;
+                } else {
+                    Slog.e(TAG, "CONSISTENCY FAILURE: Batch " + i + " is out of order");
+                    logBatchesLocked();
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    private Batch findFirstWakeupBatchLocked() {
+        final int N = mAlarmBatches.size();
+        for (int i = 0; i < N; i++) {
+            Batch b = mAlarmBatches.get(i);
+            if (b.hasWakeups()) {
+                return b;
+            }
+        }
+        return null;
+    }
+
+    void rescheduleKernelAlarmsLocked() {
+        // Schedule the next upcoming wakeup alarm.  If there is a deliverable batch
+        // prior to that which contains no wakeups, we schedule that as well.
+        if (mAlarmBatches.size() > 0) {
+            final Batch firstWakeup = findFirstWakeupBatchLocked();
+            final Batch firstBatch = mAlarmBatches.get(0);
+            if (firstWakeup != null && mNextWakeup != firstWakeup.start) {
+                mNextWakeup = firstWakeup.start;
+                setLocked(ELAPSED_REALTIME_WAKEUP, firstWakeup.start);
+            }
+            if (firstBatch != firstWakeup && mNextNonWakeup != firstBatch.start) {
+                mNextNonWakeup = firstBatch.start;
+                setLocked(ELAPSED_REALTIME, firstBatch.start);
+            }
+        }
+    }
+
+    private void removeLocked(PendingIntent operation) {
+        boolean didRemove = false;
+        for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
+            Batch b = mAlarmBatches.get(i);
+            didRemove |= b.remove(operation);
+            if (b.size() == 0) {
+                mAlarmBatches.remove(i);
+            }
+        }
+
+        if (didRemove) {
+            if (DEBUG_BATCH) {
+                Slog.v(TAG, "remove(operation) changed bounds; rebatching");
+            }
+            rebatchAllAlarmsLocked(true);
+            rescheduleKernelAlarmsLocked();
+        }
+    }
+
+    void removeLocked(String packageName) {
+        boolean didRemove = false;
+        for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
+            Batch b = mAlarmBatches.get(i);
+            didRemove |= b.remove(packageName);
+            if (b.size() == 0) {
+                mAlarmBatches.remove(i);
+            }
+        }
+
+        if (didRemove) {
+            if (DEBUG_BATCH) {
+                Slog.v(TAG, "remove(package) changed bounds; rebatching");
+            }
+            rebatchAllAlarmsLocked(true);
+            rescheduleKernelAlarmsLocked();
+        }
+    }
+
+    void removeUserLocked(int userHandle) {
+        boolean didRemove = false;
+        for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
+            Batch b = mAlarmBatches.get(i);
+            didRemove |= b.remove(userHandle);
+            if (b.size() == 0) {
+                mAlarmBatches.remove(i);
+            }
+        }
+
+        if (didRemove) {
+            if (DEBUG_BATCH) {
+                Slog.v(TAG, "remove(user) changed bounds; rebatching");
+            }
+            rebatchAllAlarmsLocked(true);
+            rescheduleKernelAlarmsLocked();
+        }
+    }
+
+    boolean lookForPackageLocked(String packageName) {
+        for (int i = 0; i < mAlarmBatches.size(); i++) {
+            Batch b = mAlarmBatches.get(i);
+            if (b.hasPackage(packageName)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private void setLocked(int type, long when) {
+        if (mNativeData != 0) {
+            // The kernel never triggers alarms with negative wakeup times
+            // so we ensure they are positive.
+            long alarmSeconds, alarmNanoseconds;
+            if (when < 0) {
+                alarmSeconds = 0;
+                alarmNanoseconds = 0;
+            } else {
+                alarmSeconds = when / 1000;
+                alarmNanoseconds = (when % 1000) * 1000 * 1000;
+            }
+            
+            set(mNativeData, type, alarmSeconds, alarmNanoseconds);
+        } else {
+            Message msg = Message.obtain();
+            msg.what = ALARM_EVENT;
+            
+            mHandler.removeMessages(ALARM_EVENT);
+            mHandler.sendMessageAtTime(msg, when);
+        }
+    }
+
     private static final void dumpAlarmList(PrintWriter pw, ArrayList<Alarm> list,
             String prefix, String label, long now) {
         for (int i=list.size()-1; i>=0; i--) {
@@ -1028,7 +1049,7 @@
     private native int setKernelTime(long nativeData, long millis);
     private native int setKernelTimezone(long nativeData, int minuteswest);
 
-    private void triggerAlarmsLocked(ArrayList<Alarm> triggerList, long nowELAPSED, long nowRTC) {
+    void triggerAlarmsLocked(ArrayList<Alarm> triggerList, long nowELAPSED, long nowRTC) {
         // batches are temporally sorted, so we need only pull from the
         // start of the list until we either empty it or hit a batch
         // that is not yet deliverable
@@ -1174,13 +1195,13 @@
                     if (DEBUG_BATCH) {
                         Slog.v(TAG, "Time changed notification from kernel; rebatching");
                     }
-                    remove(mTimeTickSender);
+                    removeImpl(mTimeTickSender);
                     rebatchAllAlarms();
                     mClockReceiver.scheduleTimeTickEvent();
                     Intent intent = new Intent(Intent.ACTION_TIME_CHANGED);
                     intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
                             | Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
-                    mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
+                    getContext().sendBroadcastAsUser(intent, UserHandle.ALL);
                 }
                 
                 synchronized (mLock) {
@@ -1214,7 +1235,7 @@
                         Alarm alarm = triggerList.get(i);
                         try {
                             if (localLOGV) Slog.v(TAG, "sending alarm " + alarm);
-                            alarm.operation.send(mContext, 0,
+                            alarm.operation.send(getContext(), 0,
                                     mBackgroundIntent.putExtra(
                                             Intent.EXTRA_ALARM_COUNT, alarm.count),
                                     mResultReceiver, mHandler);
@@ -1256,7 +1277,7 @@
                             if (alarm.repeatInterval > 0) {
                                 // This IntentSender is no longer valid, but this
                                 // is a repeating alarm, so toss the hoser.
-                                remove(alarm.operation);
+                                removeImpl(alarm.operation);
                             }
                         } catch (RuntimeException e) {
                             Slog.w(TAG, "Failure sending alarm.", e);
@@ -1318,7 +1339,7 @@
                         if (alarm.repeatInterval > 0) {
                             // This IntentSender is no longer valid, but this
                             // is a repeating alarm, so toss the hoser.
-                            remove(alarm.operation);
+                            removeImpl(alarm.operation);
                         }
                     }
                 }
@@ -1331,7 +1352,7 @@
             IntentFilter filter = new IntentFilter();
             filter.addAction(Intent.ACTION_TIME_TICK);
             filter.addAction(Intent.ACTION_DATE_CHANGED);
-            mContext.registerReceiver(this, filter);
+            getContext().registerReceiver(this, filter);
         }
         
         @Override
@@ -1362,7 +1383,7 @@
             final long tickEventDelay = nextTime - currentTime;
 
             final WorkSource workSource = null; // Let system take blame for time tick events.
-            set(ELAPSED_REALTIME, SystemClock.elapsedRealtime() + tickEventDelay, 0,
+            setImpl(ELAPSED_REALTIME, SystemClock.elapsedRealtime() + tickEventDelay, 0,
                     0, mTimeTickSender, true, workSource);
         }
 
@@ -1376,7 +1397,7 @@
             calendar.add(Calendar.DAY_OF_MONTH, 1);
 
             final WorkSource workSource = null; // Let system take blame for date change events.
-            set(RTC, calendar.getTimeInMillis(), 0, 0, mDateChangeSender, true, workSource);
+            setImpl(RTC, calendar.getTimeInMillis(), 0, 0, mDateChangeSender, true, workSource);
         }
     }
     
@@ -1387,12 +1408,12 @@
             filter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
             filter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
             filter.addDataScheme("package");
-            mContext.registerReceiver(this, filter);
+            getContext().registerReceiver(this, filter);
              // Register for events related to sdcard installation.
             IntentFilter sdFilter = new IntentFilter();
             sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
             sdFilter.addAction(Intent.ACTION_USER_STOPPED);
-            mContext.registerReceiver(this, sdFilter);
+            getContext().registerReceiver(this, sdFilter);
         }
         
         @Override
diff --git a/services/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
similarity index 99%
rename from services/java/com/android/server/AppOpsService.java
rename to services/core/java/com/android/server/AppOpsService.java
index a1a0d47..e5615c0 100644
--- a/services/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -186,9 +186,9 @@
         }
     }
 
-    public AppOpsService(File storagePath) {
+    public AppOpsService(File storagePath, Handler handler) {
         mFile = new AtomicFile(storagePath);
-        mHandler = new Handler();
+        mHandler = handler;
         readState();
     }
 
diff --git a/services/java/com/android/server/AssetAtlasService.java b/services/core/java/com/android/server/AssetAtlasService.java
similarity index 100%
rename from services/java/com/android/server/AssetAtlasService.java
rename to services/core/java/com/android/server/AssetAtlasService.java
diff --git a/services/java/com/android/server/AttributeCache.java b/services/core/java/com/android/server/AttributeCache.java
similarity index 100%
rename from services/java/com/android/server/AttributeCache.java
rename to services/core/java/com/android/server/AttributeCache.java
diff --git a/services/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java
similarity index 97%
rename from services/java/com/android/server/BatteryService.java
rename to services/core/java/com/android/server/BatteryService.java
index 5f3f894..cc9055d 100644
--- a/services/java/com/android/server/BatteryService.java
+++ b/services/core/java/com/android/server/BatteryService.java
@@ -19,6 +19,8 @@
 import android.os.BatteryStats;
 import com.android.internal.app.IBatteryStats;
 import com.android.server.am.BatteryStatsService;
+import com.android.server.lights.Light;
+import com.android.server.lights.LightsManager;
 
 import android.app.ActivityManagerNative;
 import android.content.ContentResolver;
@@ -134,13 +136,10 @@
 
     private boolean mSentLowBatteryBroadcast = false;
 
-    private BatteryListener mBatteryPropertiesListener;
-    private IBatteryPropertiesRegistrar mBatteryPropertiesRegistrar;
-
-    public BatteryService(Context context, LightsService lights) {
+    public BatteryService(Context context, LightsManager lightsManager) {
         mContext = context;
         mHandler = new Handler(true /*async*/);
-        mLed = new Led(context, lights);
+        mLed = new Led(context, lightsManager);
         mBatteryStats = BatteryStatsService.getService();
 
         mCriticalBatteryLevel = mContext.getResources().getInteger(
@@ -158,13 +157,11 @@
                     "DEVPATH=/devices/virtual/switch/invalid_charger");
         }
 
-        mBatteryPropertiesListener = new BatteryListener();
-
         IBinder b = ServiceManager.getService("batterypropreg");
-        mBatteryPropertiesRegistrar = IBatteryPropertiesRegistrar.Stub.asInterface(b);
-
+        final IBatteryPropertiesRegistrar batteryPropertiesRegistrar =
+                IBatteryPropertiesRegistrar.Stub.asInterface(b);
         try {
-            mBatteryPropertiesRegistrar.registerListener(mBatteryPropertiesListener);
+            batteryPropertiesRegistrar.registerListener(new BatteryListener());
         } catch (RemoteException e) {
             // Should never happen.
         }
@@ -688,7 +685,7 @@
     };
 
     private final class Led {
-        private final LightsService.Light mBatteryLight;
+        private final Light mBatteryLight;
 
         private final int mBatteryLowARGB;
         private final int mBatteryMediumARGB;
@@ -696,8 +693,8 @@
         private final int mBatteryLedOn;
         private final int mBatteryLedOff;
 
-        public Led(Context context, LightsService lights) {
-            mBatteryLight = lights.getLight(LightsService.LIGHT_ID_BATTERY);
+        public Led(Context context, LightsManager lights) {
+            mBatteryLight = lights.getLight(LightsManager.LIGHT_ID_BATTERY);
 
             mBatteryLowARGB = context.getResources().getInteger(
                     com.android.internal.R.integer.config_notificationsBatteryLowARGB);
@@ -723,7 +720,7 @@
                     mBatteryLight.setColor(mBatteryLowARGB);
                 } else {
                     // Flash red when battery is low and not charging
-                    mBatteryLight.setFlashing(mBatteryLowARGB, LightsService.LIGHT_FLASH_TIMED,
+                    mBatteryLight.setFlashing(mBatteryLowARGB, Light.LIGHT_FLASH_TIMED,
                             mBatteryLedOn, mBatteryLedOff);
                 }
             } else if (status == BatteryManager.BATTERY_STATUS_CHARGING
@@ -743,8 +740,14 @@
     }
 
     private final class BatteryListener extends IBatteryPropertiesListener.Stub {
+        @Override
         public void batteryPropertiesChanged(BatteryProperties props) {
-            BatteryService.this.update(props);
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                BatteryService.this.update(props);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
        }
     }
 }
diff --git a/services/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
similarity index 100%
rename from services/java/com/android/server/BluetoothManagerService.java
rename to services/core/java/com/android/server/BluetoothManagerService.java
diff --git a/services/java/com/android/server/BootReceiver.java b/services/core/java/com/android/server/BootReceiver.java
similarity index 88%
rename from services/java/com/android/server/BootReceiver.java
rename to services/core/java/com/android/server/BootReceiver.java
index da1b254..7249985 100644
--- a/services/java/com/android/server/BootReceiver.java
+++ b/services/core/java/com/android/server/BootReceiver.java
@@ -106,20 +106,33 @@
             .append("Kernel: ")
             .append(FileUtils.readTextFile(new File("/proc/version"), 1024, "...\n"))
             .append("\n").toString();
+        final String bootReason = SystemProperties.get("ro.boot.bootreason", null);
 
         String recovery = RecoverySystem.handleAftermath();
         if (recovery != null && db != null) {
             db.addText("SYSTEM_RECOVERY_LOG", headers + recovery);
         }
 
+        String lastKmsgFooter = "";
+        if (bootReason != null) {
+            lastKmsgFooter = new StringBuilder(512)
+                .append("\n")
+                .append("Boot info:\n")
+                .append("Last boot reason: ").append(bootReason).append("\n")
+                .toString();
+        }
+
         if (SystemProperties.getLong("ro.runtime.firstboot", 0) == 0) {
             String now = Long.toString(System.currentTimeMillis());
             SystemProperties.set("ro.runtime.firstboot", now);
             if (db != null) db.addText("SYSTEM_BOOT", headers);
 
             // Negative sizes mean to take the *tail* of the file (see FileUtils.readTextFile())
-            addFileToDropBox(db, prefs, headers, "/proc/last_kmsg",
-                    -LOG_SIZE, "SYSTEM_LAST_KMSG");
+            addFileWithFootersToDropBox(db, prefs, headers, lastKmsgFooter,
+                    "/proc/last_kmsg", -LOG_SIZE, "SYSTEM_LAST_KMSG");
+            addFileWithFootersToDropBox(db, prefs, headers, lastKmsgFooter,
+                    "/sys/fs/pstore/console-ramoops", -LOG_SIZE,
+                    "SYSTEM_LAST_KMSG");
             addFileToDropBox(db, prefs, headers, "/cache/recovery/log",
                     -LOG_SIZE, "SYSTEM_RECOVERY_LOG");
             addFileToDropBox(db, prefs, headers, "/data/dontpanic/apanic_console",
@@ -159,6 +172,14 @@
     private static void addFileToDropBox(
             DropBoxManager db, SharedPreferences prefs,
             String headers, String filename, int maxSize, String tag) throws IOException {
+        addFileWithFootersToDropBox(db, prefs, headers, "", filename, maxSize,
+                tag);
+    }
+
+    private static void addFileWithFootersToDropBox(
+            DropBoxManager db, SharedPreferences prefs,
+            String headers, String footers, String filename, int maxSize,
+            String tag) throws IOException {
         if (db == null || !db.isTagEnabled(tag)) return;  // Logging disabled
 
         File file = new File(filename);
@@ -174,7 +195,7 @@
         }
 
         Slog.i(TAG, "Copying " + filename + " to DropBox (" + tag + ")");
-        db.addText(tag, headers + FileUtils.readTextFile(file, maxSize, "[[TRUNCATED]]\n"));
+        db.addText(tag, headers + FileUtils.readTextFile(file, maxSize, "[[TRUNCATED]]\n") + footers);
     }
 
     private static void addAuditErrorsToDropBox(DropBoxManager db,  SharedPreferences prefs,
@@ -184,6 +205,11 @@
 
         File file = new File("/proc/last_kmsg");
         long fileTime = file.lastModified();
+        if (fileTime <= 0) {
+            file = new File("/sys/fs/pstore/console-ramoops");
+            fileTime = file.lastModified();
+        }
+
         if (fileTime <= 0) return;  // File does not exist
 
         if (prefs != null) {
diff --git a/services/java/com/android/server/BrickReceiver.java b/services/core/java/com/android/server/BrickReceiver.java
similarity index 100%
rename from services/java/com/android/server/BrickReceiver.java
rename to services/core/java/com/android/server/BrickReceiver.java
diff --git a/services/java/com/android/server/CertBlacklister.java b/services/core/java/com/android/server/CertBlacklister.java
similarity index 100%
rename from services/java/com/android/server/CertBlacklister.java
rename to services/core/java/com/android/server/CertBlacklister.java
diff --git a/services/java/com/android/server/CommonTimeManagementService.java b/services/core/java/com/android/server/CommonTimeManagementService.java
similarity index 100%
rename from services/java/com/android/server/CommonTimeManagementService.java
rename to services/core/java/com/android/server/CommonTimeManagementService.java
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
similarity index 99%
rename from services/java/com/android/server/ConnectivityService.java
rename to services/core/java/com/android/server/ConnectivityService.java
index b7a1a55..57ee031 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -26,6 +26,7 @@
 import static android.net.ConnectivityManager.TYPE_MOBILE;
 import static android.net.ConnectivityManager.TYPE_WIFI;
 import static android.net.ConnectivityManager.TYPE_WIMAX;
+import static android.net.ConnectivityManager.TYPE_PROXY;
 import static android.net.ConnectivityManager.getNetworkTypeName;
 import static android.net.ConnectivityManager.isNetworkTypeValid;
 import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
@@ -72,6 +73,7 @@
 import android.net.NetworkStateTracker;
 import android.net.NetworkUtils;
 import android.net.Proxy;
+import android.net.ProxyDataTracker;
 import android.net.ProxyProperties;
 import android.net.RouteInfo;
 import android.net.SamplingDataTracker;
@@ -736,6 +738,8 @@
                     return makeWimaxStateTracker(mContext, mTrackerHandler);
                 case TYPE_ETHERNET:
                     return EthernetDataTracker.getInstance();
+                case TYPE_PROXY:
+                    return new ProxyDataTracker();
                 default:
                     throw new IllegalArgumentException(
                             "Trying to create a NetworkStateTracker for an unknown radio type: "
diff --git a/services/java/com/android/server/ConsumerIrService.java b/services/core/java/com/android/server/ConsumerIrService.java
similarity index 100%
rename from services/java/com/android/server/ConsumerIrService.java
rename to services/core/java/com/android/server/ConsumerIrService.java
diff --git a/services/java/com/android/server/CountryDetectorService.java b/services/core/java/com/android/server/CountryDetectorService.java
similarity index 100%
rename from services/java/com/android/server/CountryDetectorService.java
rename to services/core/java/com/android/server/CountryDetectorService.java
diff --git a/services/java/com/android/server/DiskStatsService.java b/services/core/java/com/android/server/DiskStatsService.java
similarity index 100%
rename from services/java/com/android/server/DiskStatsService.java
rename to services/core/java/com/android/server/DiskStatsService.java
diff --git a/services/core/java/com/android/server/DisplayThread.java b/services/core/java/com/android/server/DisplayThread.java
new file mode 100644
index 0000000..528ba0a
--- /dev/null
+++ b/services/core/java/com/android/server/DisplayThread.java
@@ -0,0 +1,56 @@
+/*
+ * 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;
+
+import android.os.Handler;
+
+/**
+ * Shared singleton foreground thread for the system.  This is a thread for
+ * operations that affect what's on the display, which needs to have a minimum
+ * of latency.  This thread should pretty much only be used by the WindowManager,
+ * DisplayManager, and InputManager to perform quick operations in real time.
+ */
+public final class DisplayThread extends ServiceThread {
+    private static DisplayThread sInstance;
+    private static Handler sHandler;
+
+    private DisplayThread() {
+        super("android.display", android.os.Process.THREAD_PRIORITY_DISPLAY, false /*allowIo*/);
+    }
+
+    private static void ensureThreadLocked() {
+        if (sInstance == null) {
+            sInstance = new DisplayThread();
+            sInstance.start();
+            sHandler = new Handler(sInstance.getLooper());
+        }
+    }
+
+    public static DisplayThread get() {
+        synchronized (UiThread.class) {
+            ensureThreadLocked();
+            return sInstance;
+        }
+    }
+
+    public static Handler getHandler() {
+        synchronized (UiThread.class) {
+            ensureThreadLocked();
+            return sHandler;
+        }
+    }
+}
diff --git a/services/java/com/android/server/DockObserver.java b/services/core/java/com/android/server/DockObserver.java
similarity index 100%
rename from services/java/com/android/server/DockObserver.java
rename to services/core/java/com/android/server/DockObserver.java
diff --git a/services/java/com/android/server/DropBoxManagerService.java b/services/core/java/com/android/server/DropBoxManagerService.java
similarity index 100%
rename from services/java/com/android/server/DropBoxManagerService.java
rename to services/core/java/com/android/server/DropBoxManagerService.java
diff --git a/services/java/com/android/server/EntropyMixer.java b/services/core/java/com/android/server/EntropyMixer.java
similarity index 100%
rename from services/java/com/android/server/EntropyMixer.java
rename to services/core/java/com/android/server/EntropyMixer.java
diff --git a/services/java/com/android/server/EventLogTags.logtags b/services/core/java/com/android/server/EventLogTags.logtags
similarity index 100%
rename from services/java/com/android/server/EventLogTags.logtags
rename to services/core/java/com/android/server/EventLogTags.logtags
diff --git a/services/java/com/android/server/FgThread.java b/services/core/java/com/android/server/FgThread.java
similarity index 85%
rename from services/java/com/android/server/FgThread.java
rename to services/core/java/com/android/server/FgThread.java
index 3b655f2..03765db 100644
--- a/services/java/com/android/server/FgThread.java
+++ b/services/core/java/com/android/server/FgThread.java
@@ -17,7 +17,6 @@
 package com.android.server;
 
 import android.os.Handler;
-import android.os.HandlerThread;
 
 /**
  * Shared singleton foreground thread for the system.  This is a thread for regular
@@ -27,12 +26,12 @@
  * simply being a background priority), which can cause operations scheduled on it
  * to be delayed for a user-noticeable amount of time.
  */
-public final class FgThread extends HandlerThread {
+public final class FgThread extends ServiceThread {
     private static FgThread sInstance;
     private static Handler sHandler;
 
     private FgThread() {
-        super("android.fg", android.os.Process.THREAD_PRIORITY_DEFAULT);
+        super("android.fg", android.os.Process.THREAD_PRIORITY_DEFAULT, true /*allowIo*/);
     }
 
     private static void ensureThreadLocked() {
@@ -40,12 +39,6 @@
             sInstance = new FgThread();
             sInstance.start();
             sHandler = new Handler(sInstance.getLooper());
-            sHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    android.os.Process.setCanSelfBackground(false);
-                }
-            });
         }
     }
 
diff --git a/services/java/com/android/server/INativeDaemonConnectorCallbacks.java b/services/core/java/com/android/server/INativeDaemonConnectorCallbacks.java
similarity index 100%
rename from services/java/com/android/server/INativeDaemonConnectorCallbacks.java
rename to services/core/java/com/android/server/INativeDaemonConnectorCallbacks.java
diff --git a/services/java/com/android/server/IdleMaintenanceService.java b/services/core/java/com/android/server/IdleMaintenanceService.java
similarity index 100%
rename from services/java/com/android/server/IdleMaintenanceService.java
rename to services/core/java/com/android/server/IdleMaintenanceService.java
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
similarity index 99%
rename from services/java/com/android/server/InputMethodManagerService.java
rename to services/core/java/com/android/server/InputMethodManagerService.java
index a996dbd..bbec329 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -28,7 +28,7 @@
 import com.android.internal.view.IInputMethodManager;
 import com.android.internal.view.IInputMethodSession;
 import com.android.internal.view.InputBindResult;
-import com.android.server.EventLogTags;
+import com.android.server.statusbar.StatusBarManagerService;
 import com.android.server.wm.WindowManagerService;
 
 import org.xmlpull.v1.XmlPullParser;
@@ -632,7 +632,8 @@
         mImeSwitcherNotification.vibrate = null;
 
         // Tag this notification specially so SystemUI knows it's important
-        mImeSwitcherNotification.kind = new String[] { "android.system.imeswitcher" };
+        mImeSwitcherNotification.extras.putBoolean(Notification.EXTRA_ALLOW_DURING_SETUP, true);
+        mImeSwitcherNotification.category = Notification.CATEGORY_SYSTEM;
 
         Intent intent = new Intent(Settings.ACTION_SHOW_INPUT_METHOD_PICKER);
         mImeSwitchPendingIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
diff --git a/services/java/com/android/server/IntentResolver.java b/services/core/java/com/android/server/IntentResolver.java
similarity index 100%
rename from services/java/com/android/server/IntentResolver.java
rename to services/core/java/com/android/server/IntentResolver.java
diff --git a/services/java/com/android/server/IoThread.java b/services/core/java/com/android/server/IoThread.java
similarity index 84%
rename from services/java/com/android/server/IoThread.java
rename to services/core/java/com/android/server/IoThread.java
index 09f2af7..0f29857 100644
--- a/services/java/com/android/server/IoThread.java
+++ b/services/core/java/com/android/server/IoThread.java
@@ -17,19 +17,18 @@
 package com.android.server;
 
 import android.os.Handler;
-import android.os.HandlerThread;
 
 /**
  * Shared singleton I/O thread for the system.  This is a thread for non-background
  * service operations that can potential block briefly on network IO operations
  * (not waiting for data itself, but communicating with network daemons).
  */
-public final class IoThread extends HandlerThread {
+public final class IoThread extends ServiceThread {
     private static IoThread sInstance;
     private static Handler sHandler;
 
     private IoThread() {
-        super("android.io", android.os.Process.THREAD_PRIORITY_DEFAULT);
+        super("android.io", android.os.Process.THREAD_PRIORITY_DEFAULT, true /*allowIo*/);
     }
 
     private static void ensureThreadLocked() {
@@ -37,12 +36,6 @@
             sInstance = new IoThread();
             sInstance.start();
             sHandler = new Handler(sInstance.getLooper());
-            sHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    android.os.Process.setCanSelfBackground(false);
-                }
-            });
         }
     }
 
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
similarity index 100%
rename from services/java/com/android/server/LocationManagerService.java
rename to services/core/java/com/android/server/LocationManagerService.java
diff --git a/services/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java
similarity index 100%
rename from services/java/com/android/server/LockSettingsService.java
rename to services/core/java/com/android/server/LockSettingsService.java
diff --git a/services/java/com/android/server/MasterClearReceiver.java b/services/core/java/com/android/server/MasterClearReceiver.java
similarity index 92%
rename from services/java/com/android/server/MasterClearReceiver.java
rename to services/core/java/com/android/server/MasterClearReceiver.java
index 86f57d1..e570b0b 100644
--- a/services/java/com/android/server/MasterClearReceiver.java
+++ b/services/core/java/com/android/server/MasterClearReceiver.java
@@ -37,13 +37,15 @@
             }
         }
 
+        final boolean shutdown = intent.getBooleanExtra("shutdown", false);
+
         Slog.w(TAG, "!!! FACTORY RESET !!!");
         // The reboot call is blocking, so we need to do it on another thread.
         Thread thr = new Thread("Reboot") {
             @Override
             public void run() {
                 try {
-                    RecoverySystem.rebootWipeUserData(context);
+                    RecoverySystem.rebootWipeUserData(context, shutdown);
                     Log.wtf(TAG, "Still running after master clear?!");
                 } catch (IOException e) {
                     Slog.e(TAG, "Can't perform master clear/factory reset", e);
diff --git a/services/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
similarity index 100%
rename from services/java/com/android/server/MountService.java
rename to services/core/java/com/android/server/MountService.java
diff --git a/services/java/com/android/server/NativeDaemonConnector.java b/services/core/java/com/android/server/NativeDaemonConnector.java
similarity index 100%
rename from services/java/com/android/server/NativeDaemonConnector.java
rename to services/core/java/com/android/server/NativeDaemonConnector.java
diff --git a/services/java/com/android/server/NativeDaemonConnectorException.java b/services/core/java/com/android/server/NativeDaemonConnectorException.java
similarity index 100%
rename from services/java/com/android/server/NativeDaemonConnectorException.java
rename to services/core/java/com/android/server/NativeDaemonConnectorException.java
diff --git a/services/java/com/android/server/NativeDaemonEvent.java b/services/core/java/com/android/server/NativeDaemonEvent.java
similarity index 100%
rename from services/java/com/android/server/NativeDaemonEvent.java
rename to services/core/java/com/android/server/NativeDaemonEvent.java
diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
similarity index 100%
rename from services/java/com/android/server/NetworkManagementService.java
rename to services/core/java/com/android/server/NetworkManagementService.java
diff --git a/services/java/com/android/server/NetworkTimeUpdateService.java b/services/core/java/com/android/server/NetworkTimeUpdateService.java
similarity index 100%
rename from services/java/com/android/server/NetworkTimeUpdateService.java
rename to services/core/java/com/android/server/NetworkTimeUpdateService.java
diff --git a/services/java/com/android/server/NsdService.java b/services/core/java/com/android/server/NsdService.java
similarity index 97%
rename from services/java/com/android/server/NsdService.java
rename to services/core/java/com/android/server/NsdService.java
index 9379955..8df93f1 100644
--- a/services/java/com/android/server/NsdService.java
+++ b/services/core/java/com/android/server/NsdService.java
@@ -38,10 +38,13 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.io.UnsupportedEncodingException;
 import java.net.InetAddress;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
+import java.util.Locale;
+import java.util.Map;
 import java.util.concurrent.CountDownLatch;
 
 import com.android.internal.app.IBatteryStats;
@@ -443,14 +446,14 @@
                     case NativeResponseCode.SERVICE_FOUND:
                         /* NNN uniqueId serviceName regType domain */
                         if (DBG) Slog.d(TAG, "SERVICE_FOUND Raw: " + raw);
-                        servInfo = new NsdServiceInfo(cooked[2], cooked[3], null);
+                        servInfo = new NsdServiceInfo(cooked[2], cooked[3]);
                         clientInfo.mChannel.sendMessage(NsdManager.SERVICE_FOUND, 0,
                                 clientId, servInfo);
                         break;
                     case NativeResponseCode.SERVICE_LOST:
                         /* NNN uniqueId serviceName regType domain */
                         if (DBG) Slog.d(TAG, "SERVICE_LOST Raw: " + raw);
-                        servInfo = new NsdServiceInfo(cooked[2], cooked[3], null);
+                        servInfo = new NsdServiceInfo(cooked[2], cooked[3]);
                         clientInfo.mChannel.sendMessage(NsdManager.SERVICE_LOST, 0,
                                 clientId, servInfo);
                         break;
@@ -463,7 +466,7 @@
                     case NativeResponseCode.SERVICE_REGISTERED:
                         /* NNN regId serviceName regType */
                         if (DBG) Slog.d(TAG, "SERVICE_REGISTERED Raw: " + raw);
-                        servInfo = new NsdServiceInfo(cooked[2], null, null);
+                        servInfo = new NsdServiceInfo(cooked[2], null);
                         clientInfo.mChannel.sendMessage(NsdManager.REGISTER_SERVICE_SUCCEEDED,
                                 id, clientId, servInfo);
                         break;
@@ -679,9 +682,22 @@
     private boolean registerService(int regId, NsdServiceInfo service) {
         if (DBG) Slog.d(TAG, "registerService: " + regId + " " + service);
         try {
-            //Add txtlen and txtdata
-            mNativeConnector.execute("mdnssd", "register", regId, service.getServiceName(),
+            Command cmd = new Command("mdnssd", "register", regId, service.getServiceName(),
                     service.getServiceType(), service.getPort());
+
+            // Add TXT records as additional arguments.
+            Map<String, byte[]> txtRecords = service.getAttributes();
+            for (String key : txtRecords.keySet()) {
+                try {
+                    // TODO: Send encoded TXT record as bytes once NDC/netd supports binary data.
+                    cmd.appendArg(String.format(Locale.US, "%s=%s", key,
+                            new String(txtRecords.get(key), "UTF_8")));
+                } catch (UnsupportedEncodingException e) {
+                    Slog.e(TAG, "Failed to encode txtRecord " + e);
+                }
+            }
+
+            mNativeConnector.execute(cmd);
         } catch(NativeDaemonConnectorException e) {
             Slog.e(TAG, "Failed to execute registerService " + e);
             return false;
diff --git a/services/java/com/android/server/RandomBlock.java b/services/core/java/com/android/server/RandomBlock.java
similarity index 100%
rename from services/java/com/android/server/RandomBlock.java
rename to services/core/java/com/android/server/RandomBlock.java
diff --git a/services/java/com/android/server/RecognitionManagerService.java b/services/core/java/com/android/server/RecognitionManagerService.java
similarity index 100%
rename from services/java/com/android/server/RecognitionManagerService.java
rename to services/core/java/com/android/server/RecognitionManagerService.java
diff --git a/services/java/com/android/server/SamplingProfilerService.java b/services/core/java/com/android/server/SamplingProfilerService.java
similarity index 100%
rename from services/java/com/android/server/SamplingProfilerService.java
rename to services/core/java/com/android/server/SamplingProfilerService.java
diff --git a/services/java/com/android/server/SerialService.java b/services/core/java/com/android/server/SerialService.java
similarity index 100%
rename from services/java/com/android/server/SerialService.java
rename to services/core/java/com/android/server/SerialService.java
diff --git a/services/core/java/com/android/server/ServiceThread.java b/services/core/java/com/android/server/ServiceThread.java
new file mode 100644
index 0000000..bce64af
--- /dev/null
+++ b/services/core/java/com/android/server/ServiceThread.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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;
+
+import android.os.HandlerThread;
+import android.os.Process;
+import android.os.StrictMode;
+import android.util.Slog;
+
+/**
+ * Special handler thread that we create for system services that require their own loopers.
+ */
+public class ServiceThread extends HandlerThread {
+    private static final String TAG = "ServiceThread";
+
+    private final boolean mAllowIo;
+
+    public ServiceThread(String name, int priority, boolean allowIo) {
+        super(name, priority);
+        mAllowIo = allowIo;
+    }
+
+    @Override
+    public void run() {
+        Process.setCanSelfBackground(false);
+
+        // For debug builds, log event loop stalls to dropbox for analysis.
+        if (!mAllowIo && StrictMode.conditionallyEnableDebugLogging()) {
+            Slog.i(TAG, "Enabled StrictMode logging for " + getName() + " looper.");
+        }
+
+        super.run();
+    }
+}
\ No newline at end of file
diff --git a/services/java/com/android/server/ServiceWatcher.java b/services/core/java/com/android/server/ServiceWatcher.java
similarity index 100%
rename from services/java/com/android/server/ServiceWatcher.java
rename to services/core/java/com/android/server/ServiceWatcher.java
diff --git a/services/java/com/android/server/ShutdownActivity.java b/services/core/java/com/android/server/ShutdownActivity.java
similarity index 100%
rename from services/java/com/android/server/ShutdownActivity.java
rename to services/core/java/com/android/server/ShutdownActivity.java
diff --git a/services/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
similarity index 100%
rename from services/java/com/android/server/TelephonyRegistry.java
rename to services/core/java/com/android/server/TelephonyRegistry.java
diff --git a/services/java/com/android/server/TextServicesManagerService.java b/services/core/java/com/android/server/TextServicesManagerService.java
similarity index 100%
rename from services/java/com/android/server/TextServicesManagerService.java
rename to services/core/java/com/android/server/TextServicesManagerService.java
diff --git a/services/java/com/android/server/TwilightCalculator.java b/services/core/java/com/android/server/TwilightCalculator.java
similarity index 100%
rename from services/java/com/android/server/TwilightCalculator.java
rename to services/core/java/com/android/server/TwilightCalculator.java
diff --git a/services/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
similarity index 74%
rename from services/java/com/android/server/UiModeManagerService.java
rename to services/core/java/com/android/server/UiModeManagerService.java
index 062be01..f59edc7 100644
--- a/services/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -34,9 +34,9 @@
 import android.os.BatteryManager;
 import android.os.Binder;
 import android.os.Handler;
+import android.os.IBinder;
 import android.os.PowerManager;
 import android.os.RemoteException;
-import android.os.ServiceManager;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.service.dreams.Sandman;
@@ -47,9 +47,11 @@
 
 import com.android.internal.R;
 import com.android.internal.app.DisableCarModeActivity;
-import com.android.server.TwilightService.TwilightState;
+import com.android.server.twilight.TwilightListener;
+import com.android.server.twilight.TwilightManager;
+import com.android.server.twilight.TwilightState;
 
-final class UiModeManagerService extends IUiModeManager.Stub {
+final class UiModeManagerService extends SystemService {
     private static final String TAG = UiModeManager.class.getSimpleName();
     private static final boolean LOG = false;
 
@@ -57,40 +59,41 @@
     private static final boolean ENABLE_LAUNCH_CAR_DOCK_APP = true;
     private static final boolean ENABLE_LAUNCH_DESK_DOCK_APP = true;
 
-    private final Context mContext;
-    private final TwilightService mTwilightService;
-    private final Handler mHandler = new Handler();
-
     final Object mLock = new Object();
-
     private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
-    private int mLastBroadcastState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
 
-    private int mNightMode = UiModeManager.MODE_NIGHT_NO;
+    private int mLastBroadcastState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
+    int mNightMode = UiModeManager.MODE_NIGHT_NO;
+
     private boolean mCarModeEnabled = false;
     private boolean mCharging = false;
-    private final int mDefaultUiModeType;
-    private final boolean mCarModeKeepsScreenOn;
-    private final boolean mDeskModeKeepsScreenOn;
-    private final boolean mTelevision;
-
+    private int mDefaultUiModeType;
+    private boolean mCarModeKeepsScreenOn;
+    private boolean mDeskModeKeepsScreenOn;
+    private boolean mTelevision;
+    private boolean mWatch;
     private boolean mComputedNightMode;
-    private int mCurUiMode = 0;
+
+    int mCurUiMode = 0;
     private int mSetUiMode = 0;
-
     private boolean mHoldingConfiguration = false;
+
     private Configuration mConfiguration = new Configuration();
+    boolean mSystemReady;
 
-    private boolean mSystemReady;
+    private final Handler mHandler = new Handler();
 
+    private TwilightManager mTwilightManager;
     private NotificationManager mNotificationManager;
-
     private StatusBarManager mStatusBarManager;
 
-    private final PowerManager mPowerManager;
-    private final PowerManager.WakeLock mWakeLock;
+    private PowerManager.WakeLock mWakeLock;
 
-    static Intent buildHomeIntent(String category) {
+    public UiModeManagerService(Context context) {
+        super(context);
+    }
+
+    private static Intent buildHomeIntent(String category) {
         Intent intent = new Intent(Intent.ACTION_MAIN);
         intent.addCategory(category);
         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
@@ -142,28 +145,26 @@
         }
     };
 
-    private final TwilightService.TwilightListener mTwilightListener =
-            new TwilightService.TwilightListener() {
+    private final TwilightListener mTwilightListener = new TwilightListener() {
         @Override
         public void onTwilightStateChanged() {
             updateTwilight();
         }
     };
 
-    public UiModeManagerService(Context context, TwilightService twilight) {
-        mContext = context;
-        mTwilightService = twilight;
+    @Override
+    public void onStart() {
+        final Context context = getContext();
+        mTwilightManager = getLocalService(TwilightManager.class);
+        final PowerManager powerManager =
+                (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+        mWakeLock = powerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, TAG);
 
-        ServiceManager.addService(Context.UI_MODE_SERVICE, this);
-
-        mContext.registerReceiver(mDockModeReceiver,
+        context.registerReceiver(mDockModeReceiver,
                 new IntentFilter(Intent.ACTION_DOCK_EVENT));
-        mContext.registerReceiver(mBatteryReceiver,
+        context.registerReceiver(mBatteryReceiver,
                 new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
 
-        mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
-        mWakeLock = mPowerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, TAG);
-
         mConfiguration.setToDefaults();
 
         mDefaultUiModeType = context.getResources().getInteger(
@@ -173,103 +174,144 @@
         mDeskModeKeepsScreenOn = (context.getResources().getInteger(
                 com.android.internal.R.integer.config_deskDockKeepsScreenOn) == 1);
         mTelevision = context.getPackageManager().hasSystemFeature(
-                PackageManager.FEATURE_TELEVISION);
+                PackageManager.FEATURE_TELEVISION) ||
+            context.getPackageManager().hasSystemFeature(
+                    PackageManager.FEATURE_LEANBACK);
+        mWatch = context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH);
 
-        mNightMode = Settings.Secure.getInt(mContext.getContentResolver(),
+        mNightMode = Settings.Secure.getInt(context.getContentResolver(),
                 Settings.Secure.UI_NIGHT_MODE, UiModeManager.MODE_NIGHT_AUTO);
 
-        mTwilightService.registerListener(mTwilightListener, mHandler);
+        mTwilightManager.registerListener(mTwilightListener, mHandler);
+
+        publishBinderService(Context.UI_MODE_SERVICE, mService);
     }
 
-    @Override // Binder call
-    public void disableCarMode(int flags) {
-        final long ident = Binder.clearCallingIdentity();
-        try {
-            synchronized (mLock) {
-                setCarModeLocked(false);
-                if (mSystemReady) {
-                    updateLocked(0, flags);
+    private final IBinder mService = new IUiModeManager.Stub() {
+        @Override
+        public void enableCarMode(int flags) {
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    setCarModeLocked(true);
+                    if (mSystemReady) {
+                        updateLocked(flags, 0);
+                    }
                 }
+            } finally {
+                Binder.restoreCallingIdentity(ident);
             }
-        } finally {
-            Binder.restoreCallingIdentity(ident);
         }
-    }
 
-    @Override // Binder call
-    public void enableCarMode(int flags) {
-        final long ident = Binder.clearCallingIdentity();
-        try {
-            synchronized (mLock) {
-                setCarModeLocked(true);
-                if (mSystemReady) {
-                    updateLocked(flags, 0);
+        @Override
+        public void disableCarMode(int flags) {
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    setCarModeLocked(false);
+                    if (mSystemReady) {
+                        updateLocked(0, flags);
+                    }
                 }
+            } finally {
+                Binder.restoreCallingIdentity(ident);
             }
-        } finally {
-            Binder.restoreCallingIdentity(ident);
-        }
-    }
-
-    @Override // Binder call
-    public int getCurrentModeType() {
-        final long ident = Binder.clearCallingIdentity();
-        try {
-            synchronized (mLock) {
-                return mCurUiMode & Configuration.UI_MODE_TYPE_MASK;
-            }
-        } finally {
-            Binder.restoreCallingIdentity(ident);
-        }
-    }
-
-    @Override // Binder call
-    public void setNightMode(int mode) {
-        switch (mode) {
-            case UiModeManager.MODE_NIGHT_NO:
-            case UiModeManager.MODE_NIGHT_YES:
-            case UiModeManager.MODE_NIGHT_AUTO:
-                break;
-            default:
-                throw new IllegalArgumentException("Unknown mode: " + mode);
         }
 
-        final long ident = Binder.clearCallingIdentity();
-        try {
-            synchronized (mLock) {
-                if (isDoingNightModeLocked() && mNightMode != mode) {
-                    Settings.Secure.putInt(mContext.getContentResolver(),
-                            Settings.Secure.UI_NIGHT_MODE, mode);
-                    mNightMode = mode;
-                    updateLocked(0, 0);
+        @Override
+        public int getCurrentModeType() {
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    return mCurUiMode & Configuration.UI_MODE_TYPE_MASK;
                 }
+            } finally {
+                Binder.restoreCallingIdentity(ident);
             }
-        } finally {
-            Binder.restoreCallingIdentity(ident);
         }
-    }
 
-    @Override // Binder call
-    public int getNightMode() {
+        @Override
+        public void setNightMode(int mode) {
+            switch (mode) {
+                case UiModeManager.MODE_NIGHT_NO:
+                case UiModeManager.MODE_NIGHT_YES:
+                case UiModeManager.MODE_NIGHT_AUTO:
+                    break;
+                default:
+                    throw new IllegalArgumentException("Unknown mode: " + mode);
+            }
+
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    if (isDoingNightModeLocked() && mNightMode != mode) {
+                        Settings.Secure.putInt(getContext().getContentResolver(),
+                                Settings.Secure.UI_NIGHT_MODE, mode);
+                        mNightMode = mode;
+                        updateLocked(0, 0);
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
+        @Override
+        public int getNightMode() {
+            synchronized (mLock) {
+                return mNightMode;
+            }
+        }
+
+        @Override
+        protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+            if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+                    != PackageManager.PERMISSION_GRANTED) {
+
+                pw.println("Permission Denial: can't dump uimode service from from pid="
+                        + Binder.getCallingPid()
+                        + ", uid=" + Binder.getCallingUid());
+                return;
+            }
+
+            dumpImpl(pw);
+        }
+    };
+
+    void dumpImpl(PrintWriter pw) {
         synchronized (mLock) {
-            return mNightMode;
+            pw.println("Current UI Mode Service state:");
+            pw.print("  mDockState="); pw.print(mDockState);
+                    pw.print(" mLastBroadcastState="); pw.println(mLastBroadcastState);
+            pw.print("  mNightMode="); pw.print(mNightMode);
+                    pw.print(" mCarModeEnabled="); pw.print(mCarModeEnabled);
+                    pw.print(" mComputedNightMode="); pw.println(mComputedNightMode);
+            pw.print("  mCurUiMode=0x"); pw.print(Integer.toHexString(mCurUiMode));
+                    pw.print(" mSetUiMode=0x"); pw.println(Integer.toHexString(mSetUiMode));
+            pw.print("  mHoldingConfiguration="); pw.print(mHoldingConfiguration);
+                    pw.print(" mSystemReady="); pw.println(mSystemReady);
+            pw.print("  mTwilightService.getCurrentState()=");
+                    pw.println(mTwilightManager.getCurrentState());
         }
     }
 
-    void systemReady() {
-        synchronized (mLock) {
-            mSystemReady = true;
-            mCarModeEnabled = mDockState == Intent.EXTRA_DOCK_STATE_CAR;
-            updateComputedNightModeLocked();
-            updateLocked(0, 0);
+    @Override
+    public void onBootPhase(int phase) {
+        if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
+            synchronized (mLock) {
+                mSystemReady = true;
+                mCarModeEnabled = mDockState == Intent.EXTRA_DOCK_STATE_CAR;
+                updateComputedNightModeLocked();
+                updateLocked(0, 0);
+            }
         }
     }
 
-    private boolean isDoingNightModeLocked() {
+    boolean isDoingNightModeLocked() {
         return mCarModeEnabled || mDockState != Intent.EXTRA_DOCK_STATE_UNDOCKED;
     }
 
-    private void setCarModeLocked(boolean enabled) {
+    void setCarModeLocked(boolean enabled) {
         if (mCarModeEnabled != enabled) {
             mCarModeEnabled = enabled;
         }
@@ -299,8 +341,12 @@
     }
 
     private void updateConfigurationLocked() {
-        int uiMode = mTelevision ? Configuration.UI_MODE_TYPE_TELEVISION : mDefaultUiModeType;
-        if (mCarModeEnabled) {
+        int uiMode = mDefaultUiModeType;
+        if (mTelevision) {
+            uiMode = Configuration.UI_MODE_TYPE_TELEVISION;
+        } else if (mWatch) {
+            uiMode = Configuration.UI_MODE_TYPE_WATCH;
+        } else if (mCarModeEnabled) {
             uiMode = Configuration.UI_MODE_TYPE_CAR;
         } else if (isDeskDockState(mDockState)) {
             uiMode = Configuration.UI_MODE_TYPE_DESK;
@@ -344,7 +390,7 @@
         }
     }
 
-    private void updateLocked(int enableFlags, int disableFlags) {
+    void updateLocked(int enableFlags, int disableFlags) {
         String action = null;
         String oldAction = null;
         if (mLastBroadcastState == Intent.EXTRA_DOCK_STATE_CAR) {
@@ -359,7 +405,7 @@
                 adjustStatusBarCarModeLocked();
 
                 if (oldAction != null) {
-                    mContext.sendBroadcastAsUser(new Intent(oldAction), UserHandle.ALL);
+                    getContext().sendBroadcastAsUser(new Intent(oldAction), UserHandle.ALL);
                 }
                 mLastBroadcastState = Intent.EXTRA_DOCK_STATE_CAR;
                 action = UiModeManager.ACTION_ENTER_CAR_MODE;
@@ -367,7 +413,7 @@
         } else if (isDeskDockState(mDockState)) {
             if (!isDeskDockState(mLastBroadcastState)) {
                 if (oldAction != null) {
-                    mContext.sendBroadcastAsUser(new Intent(oldAction), UserHandle.ALL);
+                    getContext().sendBroadcastAsUser(new Intent(oldAction), UserHandle.ALL);
                 }
                 mLastBroadcastState = mDockState;
                 action = UiModeManager.ACTION_ENTER_DESK_MODE;
@@ -393,7 +439,7 @@
             Intent intent = new Intent(action);
             intent.putExtra("enableFlags", enableFlags);
             intent.putExtra("disableFlags", disableFlags);
-            mContext.sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT, null,
+            getContext().sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT, null,
                     mResultReceiver, null, Activity.RESULT_OK, null, null);
 
             // Attempting to make this transition a little more clean, we are going
@@ -491,7 +537,7 @@
             // activity manager take care of both the start and config
             // change.
             Intent homeIntent = buildHomeIntent(category);
-            if (Sandman.shouldStartDockApp(mContext, homeIntent)) {
+            if (Sandman.shouldStartDockApp(getContext(), homeIntent)) {
                 try {
                     int result = ActivityManagerNative.getDefault().startActivityWithConfig(
                             null, null, homeIntent, null, null, null, 0, 0,
@@ -513,14 +559,15 @@
 
         // If we did not start a dock app, then start dreaming if supported.
         if (category != null && !dockAppStarted) {
-            Sandman.startDreamWhenDockedIfAppropriate(mContext);
+            Sandman.startDreamWhenDockedIfAppropriate(getContext());
         }
     }
 
     private void adjustStatusBarCarModeLocked() {
+        final Context context = getContext();
         if (mStatusBarManager == null) {
             mStatusBarManager = (StatusBarManager)
-                    mContext.getSystemService(Context.STATUS_BAR_SERVICE);
+                    context.getSystemService(Context.STATUS_BAR_SERVICE);
         }
 
         // Fear not: StatusBarManagerService manages a list of requests to disable
@@ -536,12 +583,12 @@
 
         if (mNotificationManager == null) {
             mNotificationManager = (NotificationManager)
-                    mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+                    context.getSystemService(Context.NOTIFICATION_SERVICE);
         }
 
         if (mNotificationManager != null) {
             if (mCarModeEnabled) {
-                Intent carModeOffIntent = new Intent(mContext, DisableCarModeActivity.class);
+                Intent carModeOffIntent = new Intent(context, DisableCarModeActivity.class);
 
                 Notification n = new Notification();
                 n.icon = R.drawable.stat_notify_car_mode;
@@ -549,10 +596,10 @@
                 n.flags = Notification.FLAG_ONGOING_EVENT;
                 n.when = 0;
                 n.setLatestEventInfo(
-                        mContext,
-                        mContext.getString(R.string.car_mode_disable_notification_title),
-                        mContext.getString(R.string.car_mode_disable_notification_message),
-                        PendingIntent.getActivityAsUser(mContext, 0, carModeOffIntent, 0,
+                        context,
+                        context.getString(R.string.car_mode_disable_notification_title),
+                        context.getString(R.string.car_mode_disable_notification_message),
+                        PendingIntent.getActivityAsUser(context, 0, carModeOffIntent, 0,
                                 null, UserHandle.CURRENT));
                 mNotificationManager.notifyAsUser(null,
                         R.string.car_mode_disable_notification_title, n, UserHandle.ALL);
@@ -563,7 +610,7 @@
         }
     }
 
-    private void updateTwilight() {
+    void updateTwilight() {
         synchronized (mLock) {
             if (isDoingNightModeLocked() && mNightMode == UiModeManager.MODE_NIGHT_AUTO) {
                 updateComputedNightModeLocked();
@@ -573,36 +620,11 @@
     }
 
     private void updateComputedNightModeLocked() {
-        TwilightState state = mTwilightService.getCurrentState();
+        TwilightState state = mTwilightManager.getCurrentState();
         if (state != null) {
             mComputedNightMode = state.isNight();
         }
     }
 
-    @Override
-    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
-                != PackageManager.PERMISSION_GRANTED) {
 
-            pw.println("Permission Denial: can't dump uimode service from from pid="
-                    + Binder.getCallingPid()
-                    + ", uid=" + Binder.getCallingUid());
-            return;
-        }
-
-        synchronized (mLock) {
-            pw.println("Current UI Mode Service state:");
-            pw.print("  mDockState="); pw.print(mDockState);
-                    pw.print(" mLastBroadcastState="); pw.println(mLastBroadcastState);
-            pw.print("  mNightMode="); pw.print(mNightMode);
-                    pw.print(" mCarModeEnabled="); pw.print(mCarModeEnabled);
-                    pw.print(" mComputedNightMode="); pw.println(mComputedNightMode);
-            pw.print("  mCurUiMode=0x"); pw.print(Integer.toHexString(mCurUiMode));
-                    pw.print(" mSetUiMode=0x"); pw.println(Integer.toHexString(mSetUiMode));
-            pw.print("  mHoldingConfiguration="); pw.print(mHoldingConfiguration);
-                    pw.print(" mSystemReady="); pw.println(mSystemReady);
-            pw.print("  mTwilightService.getCurrentState()=");
-                    pw.println(mTwilightService.getCurrentState());
-        }
-    }
 }
diff --git a/services/java/com/android/server/UiThread.java b/services/core/java/com/android/server/UiThread.java
similarity index 66%
rename from services/java/com/android/server/UiThread.java
rename to services/core/java/com/android/server/UiThread.java
index 60d73aa..0beb77f 100644
--- a/services/java/com/android/server/UiThread.java
+++ b/services/core/java/com/android/server/UiThread.java
@@ -17,21 +17,18 @@
 package com.android.server;
 
 import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.StrictMode;
-import android.util.Slog;
 
 /**
  * Shared singleton thread for showing UI.  This is a foreground thread, and in
  * additional should not have operations that can take more than a few ms scheduled
  * on it to avoid UI jank.
  */
-public final class UiThread extends HandlerThread {
+public final class UiThread extends ServiceThread {
     private static UiThread sInstance;
     private static Handler sHandler;
 
     private UiThread() {
-        super("android.ui", android.os.Process.THREAD_PRIORITY_FOREGROUND);
+        super("android.ui", android.os.Process.THREAD_PRIORITY_FOREGROUND, false /*allowIo*/);
     }
 
     private static void ensureThreadLocked() {
@@ -39,19 +36,6 @@
             sInstance = new UiThread();
             sInstance.start();
             sHandler = new Handler(sInstance.getLooper());
-            sHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    //Looper.myLooper().setMessageLogging(new LogPrinter(
-                    //        Log.VERBOSE, "WindowManagerPolicy", Log.LOG_ID_SYSTEM));
-                    android.os.Process.setCanSelfBackground(false);
-
-                    // For debug builds, log event loop stalls to dropbox for analysis.
-                    if (StrictMode.conditionallyEnableDebugLogging()) {
-                        Slog.i("UiThread", "Enabled StrictMode logging for UI thread");
-                    }
-                }
-            });
         }
     }
 
diff --git a/services/java/com/android/server/UpdateLockService.java b/services/core/java/com/android/server/UpdateLockService.java
similarity index 100%
rename from services/java/com/android/server/UpdateLockService.java
rename to services/core/java/com/android/server/UpdateLockService.java
diff --git a/services/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java
similarity index 100%
rename from services/java/com/android/server/VibratorService.java
rename to services/core/java/com/android/server/VibratorService.java
diff --git a/services/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
similarity index 95%
rename from services/java/com/android/server/Watchdog.java
rename to services/core/java/com/android/server/Watchdog.java
index e17f42d..1ce073a 100644
--- a/services/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -20,18 +20,15 @@
 import android.os.Binder;
 import android.os.RemoteException;
 import com.android.server.am.ActivityManagerService;
-import com.android.server.power.PowerManagerService;
 
-import android.app.AlarmManager;
-import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.os.BatteryManager;
 import android.os.Debug;
 import android.os.Handler;
+import android.os.IPowerManager;
 import android.os.Looper;
 import android.os.Process;
 import android.os.ServiceManager;
@@ -45,7 +42,6 @@
 import java.io.FileWriter;
 import java.io.IOException;
 import java.util.ArrayList;
-import java.util.Calendar;
 
 /** This class calls its monitor every minute. Killing this process if they don't return **/
 public class Watchdog extends Thread {
@@ -80,9 +76,6 @@
     final ArrayList<HandlerChecker> mHandlerCheckers = new ArrayList<HandlerChecker>();
     final HandlerChecker mMonitorChecker;
     ContentResolver mResolver;
-    BatteryService mBattery;
-    PowerManagerService mPower;
-    AlarmManagerService mAlarm;
     ActivityManagerService mActivity;
 
     int mPhonePid;
@@ -232,15 +225,13 @@
         // And also check IO thread.
         mHandlerCheckers.add(new HandlerChecker(IoThread.getHandler(),
                 "i/o thread", DEFAULT_TIMEOUT));
+        // And the display thread.
+        mHandlerCheckers.add(new HandlerChecker(DisplayThread.getHandler(),
+                "display thread", DEFAULT_TIMEOUT));
     }
 
-    public void init(Context context, BatteryService battery,
-            PowerManagerService power, AlarmManagerService alarm,
-            ActivityManagerService activity) {
+    public void init(Context context, ActivityManagerService activity) {
         mResolver = context.getContentResolver();
-        mBattery = battery;
-        mPower = power;
-        mAlarm = alarm;
         mActivity = activity;
 
         context.registerReceiver(new RebootRequestReceiver(),
@@ -277,15 +268,16 @@
         }
     }
 
-    public void addThread(Handler thread, String name) {
-        addThread(thread, name, DEFAULT_TIMEOUT);
+    public void addThread(Handler thread) {
+        addThread(thread, DEFAULT_TIMEOUT);
     }
 
-    public void addThread(Handler thread, String name, long timeoutMillis) {
+    public void addThread(Handler thread, long timeoutMillis) {
         synchronized (this) {
             if (isAlive()) {
                 throw new RuntimeException("Threads can't be added once the Watchdog is running");
             }
+            final String name = thread.getLooper().getThread().getName();
             mHandlerCheckers.add(new HandlerChecker(thread, name, timeoutMillis));
         }
     }
@@ -295,8 +287,11 @@
      */
     void rebootSystem(String reason) {
         Slog.i(TAG, "Rebooting system because: " + reason);
-        PowerManagerService pms = (PowerManagerService) ServiceManager.getService("power");
-        pms.reboot(false, reason, false);
+        IPowerManager pms = (IPowerManager)ServiceManager.getService(Context.POWER_SERVICE);
+        try {
+            pms.reboot(false, reason, false);
+        } catch (RemoteException ex) {
+        }
     }
 
     private int evaluateCheckerCompletionLocked() {
diff --git a/services/java/com/android/server/WiredAccessoryManager.java b/services/core/java/com/android/server/WiredAccessoryManager.java
similarity index 100%
rename from services/java/com/android/server/WiredAccessoryManager.java
rename to services/core/java/com/android/server/WiredAccessoryManager.java
diff --git a/services/java/com/android/server/accounts/AccountAuthenticatorCache.java b/services/core/java/com/android/server/accounts/AccountAuthenticatorCache.java
similarity index 100%
rename from services/java/com/android/server/accounts/AccountAuthenticatorCache.java
rename to services/core/java/com/android/server/accounts/AccountAuthenticatorCache.java
diff --git a/services/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
similarity index 100%
rename from services/java/com/android/server/accounts/AccountManagerService.java
rename to services/core/java/com/android/server/accounts/AccountManagerService.java
diff --git a/services/java/com/android/server/accounts/IAccountAuthenticatorCache.java b/services/core/java/com/android/server/accounts/IAccountAuthenticatorCache.java
similarity index 100%
rename from services/java/com/android/server/accounts/IAccountAuthenticatorCache.java
rename to services/core/java/com/android/server/accounts/IAccountAuthenticatorCache.java
diff --git a/services/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
similarity index 100%
rename from services/java/com/android/server/am/ActiveServices.java
rename to services/core/java/com/android/server/am/ActiveServices.java
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
similarity index 97%
rename from services/java/com/android/server/am/ActivityManagerService.java
rename to services/core/java/com/android/server/am/ActivityManagerService.java
index 2150aa9..0cca44c 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -24,15 +24,19 @@
 import static com.android.server.Watchdog.NATIVE_STACKS_OF_INTEREST;
 import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
 import static org.xmlpull.v1.XmlPullParser.START_TAG;
-
 import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID;
 
 import android.app.AppOpsManager;
+import android.app.IActivityContainer;
+import android.app.IActivityContainerCallback;
 import android.appwidget.AppWidgetManager;
+import android.graphics.Rect;
 import android.util.ArrayMap;
+
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.app.IAppOpsService;
+import com.android.internal.app.ProcessMap;
 import com.android.internal.app.ProcessStats;
 import com.android.internal.os.BackgroundThread;
 import com.android.internal.os.BatteryStatsImpl;
@@ -46,14 +50,14 @@
 import com.android.server.AppOpsService;
 import com.android.server.AttributeCache;
 import com.android.server.IntentResolver;
-import com.android.internal.app.ProcessMap;
-import com.android.server.SystemServer;
+import com.android.server.LocalServices;
+import com.android.server.ServiceThread;
+import com.android.server.SystemService;
 import com.android.server.Watchdog;
 import com.android.server.am.ActivityStack.ActivityState;
 import com.android.server.firewall.IntentFirewall;
 import com.android.server.pm.UserManagerService;
 import com.android.server.wm.AppTransition;
-import com.android.server.wm.StackBox;
 import com.android.server.wm.WindowManagerService;
 import com.google.android.collect.Lists;
 import com.google.android.collect.Maps;
@@ -67,8 +71,8 @@
 import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.ActivityManager.RunningTaskInfo;
-import android.app.ActivityManager.StackBoxInfo;
 import android.app.ActivityManager.StackInfo;
+import android.app.ActivityManagerInternal;
 import android.app.ActivityManagerNative;
 import android.app.ActivityOptions;
 import android.app.ActivityThread;
@@ -133,6 +137,7 @@
 import android.os.Debug;
 import android.os.DropBoxManager;
 import android.os.Environment;
+import android.os.FactoryTest;
 import android.os.FileObserver;
 import android.os.FileUtils;
 import android.os.Handler;
@@ -330,8 +335,6 @@
 
     public IntentFirewall mIntentFirewall;
 
-    private final boolean mHeadless;
-
     // Whether we should show our dialogs (ANR, crash, etc) or just perform their
     // default actuion automatically.  Important for devices without direct input
     // devices.
@@ -746,7 +749,7 @@
         }
     }
 
-    private static ThreadLocal<Identity> sCallerIdentity = new ThreadLocal<Identity>();
+    private static final ThreadLocal<Identity> sCallerIdentity = new ThreadLocal<Identity>();
 
     /**
      * All information we have collected about the runtime performance of
@@ -796,9 +799,8 @@
     /**
      * Used to control how we initialize the service.
      */
-    boolean mStartRunning = false;
     ComponentName mTopComponent;
-    String mTopAction;
+    String mTopAction = Intent.ACTION_MAIN;
     String mTopData;
     boolean mProcessesReady = false;
     boolean mSystemReady = false;
@@ -928,6 +930,11 @@
      */
     boolean mDidDexOpt;
 
+    /**
+     * Set if the systemServer made a call to enterSafeMode.
+     */
+    boolean mSafeMode;
+
     String mDebugApp = null;
     boolean mWaitForDebugger = false;
     boolean mDebugTransient = false;
@@ -995,8 +1002,7 @@
 
     WindowManagerService mWindowManager;
 
-    static ActivityManagerService mSelf;
-    static ActivityThread mSystemThread;
+    final ActivityThread mSystemThread;
 
     int mCurrentUserId = 0;
     private UserManagerService mUserManager;
@@ -1074,10 +1080,13 @@
      */
     private boolean mUserIsMonkey;
 
-    final Handler mHandler = new Handler() {
-        //public Handler() {
-        //    if (localLOGV) Slog.v(TAG, "Handler started!");
-        //}
+    final ServiceThread mHandlerThread;
+    final MainHandler mHandler;
+
+    final class MainHandler extends Handler {
+        public MainHandler(Looper looper) {
+            super(looper, null, true);
+        }
 
         @Override
         public void handleMessage(Message msg) {
@@ -1328,7 +1337,7 @@
                     String pkg = bundle.getString("pkg");
                     String reason = bundle.getString("reason");
                     forceStopPackageLocked(pkg, appid, restart, false, true, false,
-                            false, UserHandle.USER_ALL, reason);
+                            UserHandle.USER_ALL, reason);
                 }
             } break;
             case FINALIZE_PENDING_INTENT_MSG: {
@@ -1746,38 +1755,34 @@
         }
     };
 
-    public static void setSystemProcess() {
+    public void setSystemProcess() {
         try {
-            ActivityManagerService m = mSelf;
-
-            ServiceManager.addService(Context.ACTIVITY_SERVICE, m, true);
-            ServiceManager.addService(ProcessStats.SERVICE_NAME, m.mProcessStats);
-            ServiceManager.addService("meminfo", new MemBinder(m));
-            ServiceManager.addService("gfxinfo", new GraphicsBinder(m));
-            ServiceManager.addService("dbinfo", new DbBinder(m));
+            ServiceManager.addService(Context.ACTIVITY_SERVICE, this, true);
+            ServiceManager.addService(ProcessStats.SERVICE_NAME, mProcessStats);
+            ServiceManager.addService("meminfo", new MemBinder(this));
+            ServiceManager.addService("gfxinfo", new GraphicsBinder(this));
+            ServiceManager.addService("dbinfo", new DbBinder(this));
             if (MONITOR_CPU_USAGE) {
-                ServiceManager.addService("cpuinfo", new CpuBinder(m));
+                ServiceManager.addService("cpuinfo", new CpuBinder(this));
             }
-            ServiceManager.addService("permission", new PermissionController(m));
+            ServiceManager.addService("permission", new PermissionController(this));
 
-            ApplicationInfo info =
-                mSelf.mContext.getPackageManager().getApplicationInfo(
-                            "android", STOCK_PM_FLAGS);
+            ApplicationInfo info = mContext.getPackageManager().getApplicationInfo(
+                    "android", STOCK_PM_FLAGS);
             mSystemThread.installSystemApplicationInfo(info);
 
-            synchronized (mSelf) {
-                ProcessRecord app = mSelf.newProcessRecordLocked(info,
-                        info.processName, false);
+            synchronized (this) {
+                ProcessRecord app = newProcessRecordLocked(info, info.processName, false);
                 app.persistent = true;
                 app.pid = MY_PID;
                 app.maxAdj = ProcessList.SYSTEM_ADJ;
-                app.makeActive(mSystemThread.getApplicationThread(), mSelf.mProcessStats);
-                mSelf.mProcessNames.put(app.processName, app.uid, app);
-                synchronized (mSelf.mPidsSelfLocked) {
-                    mSelf.mPidsSelfLocked.put(app.pid, app);
+                app.makeActive(mSystemThread.getApplicationThread(), mProcessStats);
+                mProcessNames.put(app.processName, app.uid, app);
+                synchronized (mPidsSelfLocked) {
+                    mPidsSelfLocked.put(app.pid, app);
                 }
-                mSelf.updateLruProcessLocked(app, false, null);
-                mSelf.updateOomAdjLocked();
+                updateLruProcessLocked(app, false, null);
+                updateOomAdjLocked();
             }
         } catch (PackageManager.NameNotFoundException e) {
             throw new RuntimeException(
@@ -1788,105 +1793,17 @@
     public void setWindowManager(WindowManagerService wm) {
         mWindowManager = wm;
         mStackSupervisor.setWindowManager(wm);
-        wm.createStack(HOME_STACK_ID, -1, StackBox.TASK_STACK_GOES_OVER, 1.0f);
     }
 
     public void startObservingNativeCrashes() {
-        final NativeCrashListener ncl = new NativeCrashListener();
+        final NativeCrashListener ncl = new NativeCrashListener(this);
         ncl.start();
     }
 
-    public static final Context main(int factoryTest) {
-        AThread thr = new AThread();
-        thr.start();
-
-        synchronized (thr) {
-            while (thr.mService == null) {
-                try {
-                    thr.wait();
-                } catch (InterruptedException e) {
-                }
-            }
-        }
-
-        ActivityManagerService m = thr.mService;
-        mSelf = m;
-        ActivityThread at = ActivityThread.systemMain();
-        mSystemThread = at;
-        Context context = at.getSystemContext();
-        context.setTheme(android.R.style.Theme_Holo);
-        m.mContext = context;
-        m.mFactoryTest = factoryTest;
-        m.mIntentFirewall = new IntentFirewall(m.new IntentFirewallInterface());
-
-        m.mStackSupervisor = new ActivityStackSupervisor(m, context, thr.mLooper);
-
-        m.mBatteryStatsService.publish(context);
-        m.mUsageStatsService.publish(context);
-        m.mAppOpsService.publish(context);
-
-        synchronized (thr) {
-            thr.mReady = true;
-            thr.notifyAll();
-        }
-
-        m.startRunning(null, null, null, null);
-
-        return context;
-    }
-
-    public static ActivityManagerService self() {
-        return mSelf;
-    }
-
     public IAppOpsService getAppOpsService() {
         return mAppOpsService;
     }
 
-    static class AThread extends Thread {
-        ActivityManagerService mService;
-        Looper mLooper;
-        boolean mReady = false;
-
-        public AThread() {
-            super("ActivityManager");
-        }
-
-        @Override
-        public void run() {
-            Looper.prepare();
-
-            android.os.Process.setThreadPriority(
-                    android.os.Process.THREAD_PRIORITY_FOREGROUND);
-            android.os.Process.setCanSelfBackground(false);
-
-            ActivityManagerService m = new ActivityManagerService();
-
-            synchronized (this) {
-                mService = m;
-                mLooper = Looper.myLooper();
-                Watchdog.getInstance().addThread(new Handler(mLooper), getName());
-                notifyAll();
-            }
-
-            synchronized (this) {
-                while (!mReady) {
-                    try {
-                        wait();
-                    } catch (InterruptedException e) {
-                    }
-                }
-            }
-
-            // For debug builds, log event loop stalls to dropbox for analysis.
-            if (StrictMode.conditionallyEnableDebugLogging()) {
-                Slog.i(TAG, "Enabled StrictMode logging for AThread's Looper");
-            }
-
-            Looper.loop();
-        }
-    }
-
     static class MemBinder extends Binder {
         ActivityManagerService mActivityManagerService;
         MemBinder(ActivityManagerService activityManagerService) {
@@ -1971,22 +1888,54 @@
         }
     }
 
-    private ActivityManagerService() {
+    public static final class Lifecycle extends SystemService {
+        private final ActivityManagerService mService;
+
+        public Lifecycle(Context context) {
+            super(context);
+            mService = new ActivityManagerService(context);
+        }
+
+        @Override
+        public void onStart() {
+            mService.start();
+        }
+
+        public ActivityManagerService getService() {
+            return mService;
+        }
+    }
+
+    // Note: This method is invoked on the main thread but may need to attach various
+    // handlers to other threads.  So take care to be explicit about the looper.
+    public ActivityManagerService(Context systemContext) {
+        mContext = systemContext;
+        mFactoryTest = FactoryTest.getMode();
+        mSystemThread = ActivityThread.currentActivityThread();
+
         Slog.i(TAG, "Memory class: " + ActivityManager.staticGetMemoryClass());
 
-        mFgBroadcastQueue = new BroadcastQueue(this, "foreground", BROADCAST_FG_TIMEOUT, false);
-        mBgBroadcastQueue = new BroadcastQueue(this, "background", BROADCAST_BG_TIMEOUT, true);
+        mHandlerThread = new ServiceThread(TAG,
+                android.os.Process.THREAD_PRIORITY_FOREGROUND, false /*allowIo*/);
+        mHandlerThread.start();
+        mHandler = new MainHandler(mHandlerThread.getLooper());
+
+        mFgBroadcastQueue = new BroadcastQueue(this, mHandler,
+                "foreground", BROADCAST_FG_TIMEOUT, false);
+        mBgBroadcastQueue = new BroadcastQueue(this, mHandler,
+                "background", BROADCAST_BG_TIMEOUT, true);
         mBroadcastQueues[0] = mFgBroadcastQueue;
         mBroadcastQueues[1] = mBgBroadcastQueue;
 
         mServices = new ActiveServices(this);
         mProviderMap = new ProviderMap(this);
 
+        // TODO: Move creation of battery stats service outside of activity manager service.
         File dataDir = Environment.getDataDirectory();
         File systemDir = new File(dataDir, "system");
         systemDir.mkdirs();
         mBatteryStatsService = new BatteryStatsService(new File(
-                systemDir, "batterystats.bin").toString());
+                systemDir, "batterystats.bin").toString(), mHandler);
         mBatteryStatsService.getActiveStatistics().readLocked();
         mBatteryStatsService.getActiveStatistics().writeAsyncLocked();
         mOnBattery = DEBUG_POWER ? true
@@ -1996,12 +1945,10 @@
         mProcessStats = new ProcessStatsService(this, new File(systemDir, "procstats"));
 
         mUsageStatsService = new UsageStatsService(new File(systemDir, "usagestats").toString());
-        mAppOpsService = new AppOpsService(new File(systemDir, "appops.xml"));
+        mAppOpsService = new AppOpsService(new File(systemDir, "appops.xml"), mHandler);
 
         mGrantFile = new AtomicFile(new File(systemDir, "urigrants.xml"));
 
-        mHeadless = "1".equals(SystemProperties.get("ro.config.headless", "0"));
-
         // User 0 is the first and only user that runs at boot.
         mStartedUsers.put(0, new UserStartedState(new UserHandle(0), true));
         mUserLru.add(Integer.valueOf(0));
@@ -2016,10 +1963,9 @@
         mConfigurationSeq = mConfiguration.seq = 1;
         mProcessCpuTracker.init();
 
-        mCompatModePackages = new CompatModePackages(this, systemDir);
-
-        // Add ourself to the Watchdog monitors.
-        Watchdog.getInstance().addMonitor(this);
+        mCompatModePackages = new CompatModePackages(this, systemDir, mHandler);
+        mIntentFirewall = new IntentFirewall(new IntentFirewallInterface(), mHandler);
+        mStackSupervisor = new ActivityStackSupervisor(this);
 
         mProcessCpuThread = new Thread("CpuTracker") {
             @Override
@@ -2050,7 +1996,19 @@
                 }
             }
         };
+
+        Watchdog.getInstance().addMonitor(this);
+        Watchdog.getInstance().addThread(mHandler);
+    }
+
+    private void start() {
         mProcessCpuThread.start();
+
+        mBatteryStatsService.publish(mContext);
+        mUsageStatsService.publish(mContext);
+        mAppOpsService.publish(mContext);
+
+        LocalServices.addService(ActivityManagerInternal.class, new LocalService());
     }
 
     @Override
@@ -2746,13 +2704,13 @@
                 }
                 gids[0] = UserHandle.getSharedAppGid(UserHandle.getAppId(uid));
             }
-            if (mFactoryTest != SystemServer.FACTORY_TEST_OFF) {
-                if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
+            if (mFactoryTest != FactoryTest.FACTORY_TEST_OFF) {
+                if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL
                         && mTopComponent != null
                         && app.processName.equals(mTopComponent.getPackageName())) {
                     uid = 0;
                 }
-                if (mFactoryTest == SystemServer.FACTORY_TEST_HIGH_LEVEL
+                if (mFactoryTest == FactoryTest.FACTORY_TEST_HIGH_LEVEL
                         && (app.info.flags&ApplicationInfo.FLAG_FACTORY_TEST) != 0) {
                     uid = 0;
                 }
@@ -2767,7 +2725,7 @@
             // Run the app in safe mode if its manifest requests so or the
             // system is booted in safe mode.
             if ((app.info.flags & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0 ||
-                SystemServer.inSafeMode == true) {
+                mSafeMode == true) {
                 debugFlags |= Zygote.DEBUG_ENABLE_SAFEMODE;
             }
             if ("1".equals(SystemProperties.get("debug.checkjni"))) {
@@ -2867,21 +2825,14 @@
     Intent getHomeIntent() {
         Intent intent = new Intent(mTopAction, mTopData != null ? Uri.parse(mTopData) : null);
         intent.setComponent(mTopComponent);
-        if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
+        if (mFactoryTest != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
             intent.addCategory(Intent.CATEGORY_HOME);
         }
         return intent;
     }
 
     boolean startHomeActivityLocked(int userId) {
-        if (mHeadless) {
-            // Added because none of the other calls to ensureBootCompleted seem to fire
-            // when running headless.
-            ensureBootCompleted();
-            return false;
-        }
-
-        if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
+        if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL
                 && mTopAction == null) {
             // We are running in factory test mode, but unable to find
             // the factory test app, so just sit around displaying the
@@ -2945,14 +2896,14 @@
         // version than the last one shown, and we are not running in
         // low-level factory test mode.
         final ContentResolver resolver = mContext.getContentResolver();
-        if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL &&
+        if (mFactoryTest != FactoryTest.FACTORY_TEST_LOW_LEVEL &&
                 Settings.Global.getInt(resolver,
                         Settings.Global.DEVICE_PROVISIONED, 0) != 0) {
             mCheckedForSetup = true;
 
             // See if we should be showing the platform update setup UI.
             Intent intent = new Intent(Intent.ACTION_UPGRADE_SETUP);
-            List<ResolveInfo> ris = mSelf.mContext.getPackageManager()
+            List<ResolveInfo> ris = mContext.getPackageManager()
                     .queryIntentActivities(intent, PackageManager.GET_META_DATA);
 
             // We don't allow third party apps to replace this.
@@ -2980,7 +2931,7 @@
                     intent.setComponent(new ComponentName(
                             ri.activityInfo.packageName, ri.activityInfo.name));
                     mStackSupervisor.startActivityLocked(null, intent, null, ri.activityInfo,
-                            null, null, 0, 0, 0, null, 0, null, false, null);
+                            null, null, 0, 0, 0, null, 0, null, false, null, null);
                 }
             }
         }
@@ -3138,7 +3089,7 @@
         // TODO: Switch to user app stacks here.
         return mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent, resolvedType,
                 resultTo, resultWho, requestCode, startFlags, profileFile, profileFd,
-                null, null, options, userId);
+                null, null, options, userId, null);
     }
 
     @Override
@@ -3153,7 +3104,7 @@
         // TODO: Switch to user app stacks here.
         mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent, resolvedType,
                 resultTo, resultWho, requestCode, startFlags, profileFile, profileFd,
-                res, null, options, UserHandle.getCallingUserId());
+                res, null, options, UserHandle.getCallingUserId(), null);
         return res;
     }
 
@@ -3168,7 +3119,7 @@
         // TODO: Switch to user app stacks here.
         int ret = mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent,
                 resolvedType, resultTo, resultWho, requestCode, startFlags,
-                null, null, null, config, options, userId);
+                null, null, null, config, options, userId, null);
         return ret;
     }
 
@@ -3200,7 +3151,7 @@
             }
         }
         int ret = pir.sendInner(0, fillInIntent, resolvedType, null, null,
-                resultTo, resultWho, requestCode, flagsMask, flagsValues, options);
+                resultTo, resultWho, requestCode, flagsMask, flagsValues, options, null);
         return ret;
     }
 
@@ -3299,7 +3250,7 @@
             int res = mStackSupervisor.startActivityLocked(r.app.thread, intent,
                     r.resolvedType, aInfo, resultTo != null ? resultTo.appToken : null,
                     resultWho, requestCode, -1, r.launchedFromUid, r.launchedFromPackage, 0,
-                    options, false, null);
+                    options, false, null, null);
             Binder.restoreCallingIdentity(origId);
 
             r.finishing = wasFinishing;
@@ -3312,7 +3263,8 @@
 
     final int startActivityInPackage(int uid, String callingPackage,
             Intent intent, String resolvedType, IBinder resultTo,
-            String resultWho, int requestCode, int startFlags, Bundle options, int userId) {
+            String resultWho, int requestCode, int startFlags, Bundle options, int userId,
+                    IActivityContainer container) {
 
         userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,
                 false, true, "startActivityInPackage", null);
@@ -3320,7 +3272,7 @@
         // TODO: Switch to user app stacks here.
         int ret = mStackSupervisor.startActivityMayWait(null, uid, callingPackage, intent, resolvedType,
                 resultTo, resultWho, requestCode, startFlags,
-                null, null, null, null, options, userId);
+                null, null, null, null, options, userId, container);
         return ret;
     }
 
@@ -3624,9 +3576,13 @@
      */
     private final void handleAppDiedLocked(ProcessRecord app,
             boolean restarting, boolean allowRestart) {
+        int pid = app.pid;
         cleanUpApplicationRecordLocked(app, restarting, allowRestart, -1);
         if (!restarting) {
             removeLruProcessLocked(app);
+            if (pid > 0) {
+                ProcessList.remove(pid);
+            }
         }
 
         if (mProfileProc == app) {
@@ -4515,7 +4471,7 @@
 
     private void forceStopPackageLocked(final String packageName, int uid, String reason) {
         forceStopPackageLocked(packageName, UserHandle.getAppId(uid), false,
-                false, true, false, false, UserHandle.getUserId(uid), reason);
+                false, true, false, UserHandle.getUserId(uid), reason);
         Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
                 Uri.fromParts("package", packageName, null));
         if (!mProcessesReady) {
@@ -4531,7 +4487,7 @@
     }
 
     private void forceStopUserLocked(int userId, String reason) {
-        forceStopPackageLocked(null, -1, false, false, true, false, false, userId, reason);
+        forceStopPackageLocked(null, -1, false, false, true, false, userId, reason);
         Intent intent = new Intent(Intent.ACTION_USER_STOPPED);
         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
                 | Intent.FLAG_RECEIVER_FOREGROUND);
@@ -4616,7 +4572,7 @@
 
     private final boolean forceStopPackageLocked(String name, int appId,
             boolean callerWillRestart, boolean purgeCache, boolean doit,
-            boolean evenPersistent, boolean uninstalling, int userId, String reason) {
+            boolean evenPersistent, int userId, String reason) {
         int i;
         int N;
 
@@ -4708,7 +4664,7 @@
         // Remove transient permissions granted from/to this package/user
         removeUriPermissionsForPackageLocked(name, userId, false);
 
-        if (name == null || uninstalling) {
+        if (name == null) {
             // Remove pending intents.  For now we only do this when force
             // stopping users, because we have some problems when doing this
             // for packages -- app widgets are not currently cleaned up for
@@ -5021,7 +4977,7 @@
         // See if the top visible activity is waiting to run in this process...
         if (normalMode) {
             try {
-                if (mStackSupervisor.attachApplicationLocked(app, mHeadless)) {
+                if (mStackSupervisor.attachApplicationLocked(app)) {
                     didSomething = true;
                 }
             } catch (Exception e) {
@@ -5153,7 +5109,7 @@
                 if (pkgs != null) {
                     for (String pkg : pkgs) {
                         synchronized (ActivityManagerService.this) {
-                            if (forceStopPackageLocked(pkg, -1, false, false, false, false, false, 0,
+                            if (forceStopPackageLocked(pkg, -1, false, false, false, false, 0,
                                     "finished booting")) {
                                 setResultCode(Activity.RESULT_OK);
                                 return;
@@ -5178,7 +5134,7 @@
                 }
             }
             
-            if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
+            if (mFactoryTest != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
                 // Start looking for apps that are abusing wake locks.
                 Message nmsg = mHandler.obtainMessage(CHECK_EXCESSIVE_WAKE_LOCKS_MSG);
                 mHandler.sendMessageDelayed(nmsg, POWER_CHECK_DELAY);
@@ -7128,23 +7084,52 @@
     }
 
     @Override
-    public int createStack(int taskId, int relativeStackBoxId, int position, float weight) {
+    public IBinder getHomeActivityToken() throws RemoteException {
         enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
-                "createStack()");
-        if (DEBUG_STACK) Slog.d(TAG, "createStack: taskId=" + taskId + " relStackBoxId=" +
-                relativeStackBoxId + " position=" + position + " weight=" + weight);
+                "getHomeActivityToken()");
         synchronized (this) {
-            long ident = Binder.clearCallingIdentity();
-            try {
-                int stackId = mStackSupervisor.createStack();
-                mWindowManager.createStack(stackId, relativeStackBoxId, position, weight);
-                if (taskId > 0) {
-                    moveTaskToStack(taskId, stackId, true);
-                }
-                return stackId;
-            } finally {
-                Binder.restoreCallingIdentity(ident);
+            return mStackSupervisor.getHomeActivityToken();
+        }
+    }
+
+    @Override
+    public IActivityContainer createActivityContainer(IBinder parentActivityToken,
+            IActivityContainerCallback callback) throws RemoteException {
+        enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
+                "createActivityContainer()");
+        synchronized (this) {
+            if (parentActivityToken == null) {
+                throw new IllegalArgumentException("parent token must not be null");
             }
+            ActivityRecord r = ActivityRecord.forToken(parentActivityToken);
+            if (r == null) {
+                return null;
+            }
+            if (callback == null) {
+                throw new IllegalArgumentException("callback must not be null");
+            }
+            return mStackSupervisor.createActivityContainer(r, callback);
+        }
+    }
+
+    @Override
+    public void deleteActivityContainer(IActivityContainer container) throws RemoteException {
+        enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
+                "deleteActivityContainer()");
+        synchronized (this) {
+            mStackSupervisor.deleteActivityContainer(container);
+        }
+    }
+
+    @Override
+    public IActivityContainer getEnclosingActivityContainer(IBinder activityToken)
+            throws RemoteException {
+        synchronized (this) {
+            ActivityStack stack = ActivityRecord.getStackLocked(activityToken);
+            if (stack != null) {
+                return stack.mActivityContainer;
+            }
+            return null;
         }
     }
 
@@ -7169,99 +7154,40 @@
     }
 
     @Override
-    public void resizeStackBox(int stackBoxId, float weight) {
+    public void resizeStack(int stackBoxId, Rect bounds) {
         enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
                 "resizeStackBox()");
         long ident = Binder.clearCallingIdentity();
         try {
-            mWindowManager.resizeStackBox(stackBoxId, weight);
-        } finally {
-            Binder.restoreCallingIdentity(ident);
-        }
-    }
-
-    private ArrayList<StackInfo> getStacks() {
-        synchronized (this) {
-            ArrayList<ActivityManager.StackInfo> list = new ArrayList<ActivityManager.StackInfo>();
-            ArrayList<ActivityStack> stacks = mStackSupervisor.getStacks();
-            for (ActivityStack stack : stacks) {
-                ActivityManager.StackInfo stackInfo = new ActivityManager.StackInfo();
-                int stackId = stack.mStackId;
-                stackInfo.stackId = stackId;
-                stackInfo.bounds = mWindowManager.getStackBounds(stackId);
-                ArrayList<TaskRecord> tasks = stack.getAllTasks();
-                final int numTasks = tasks.size();
-                int[] taskIds = new int[numTasks];
-                String[] taskNames = new String[numTasks];
-                for (int i = 0; i < numTasks; ++i) {
-                    final TaskRecord task = tasks.get(i);
-                    taskIds[i] = task.taskId;
-                    taskNames[i] = task.origActivity != null ? task.origActivity.flattenToString()
-                            : task.realActivity != null ? task.realActivity.flattenToString()
-                            : task.getTopActivity() != null ? task.getTopActivity().packageName
-                            : "unknown";
-                }
-                stackInfo.taskIds = taskIds;
-                stackInfo.taskNames = taskNames;
-                list.add(stackInfo);
-            }
-            return list;
-        }
-    }
-
-    private void addStackInfoToStackBoxInfo(StackBoxInfo stackBoxInfo, List<StackInfo> stackInfos) {
-        final int stackId = stackBoxInfo.stackId;
-        if (stackId >= 0) {
-            for (StackInfo stackInfo : stackInfos) {
-                if (stackId == stackInfo.stackId) {
-                    stackBoxInfo.stack = stackInfo;
-                    stackInfos.remove(stackInfo);
-                    return;
-                }
-            }
-        } else {
-            addStackInfoToStackBoxInfo(stackBoxInfo.children[0], stackInfos);
-            addStackInfoToStackBoxInfo(stackBoxInfo.children[1], stackInfos);
-        }
-    }
-
-    @Override
-    public List<StackBoxInfo> getStackBoxes() {
-        enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
-                "getStackBoxes()");
-        long ident = Binder.clearCallingIdentity();
-        try {
-            List<StackBoxInfo> stackBoxInfos = mWindowManager.getStackBoxInfos();
-            synchronized (this) {
-                List<StackInfo> stackInfos = getStacks();
-                for (StackBoxInfo stackBoxInfo : stackBoxInfos) {
-                    addStackInfoToStackBoxInfo(stackBoxInfo, stackInfos);
-                }
-            }
-            return stackBoxInfos;
+            mWindowManager.resizeStack(stackBoxId, bounds);
         } finally {
             Binder.restoreCallingIdentity(ident);
         }
     }
 
     @Override
-    public StackBoxInfo getStackBoxInfo(int stackBoxId) {
+    public List<StackInfo> getAllStackInfos() {
         enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
-                "getStackBoxInfo()");
+                "getAllStackInfos()");
         long ident = Binder.clearCallingIdentity();
         try {
-            List<StackBoxInfo> stackBoxInfos = mWindowManager.getStackBoxInfos();
-            StackBoxInfo info = null;
             synchronized (this) {
-                List<StackInfo> stackInfos = getStacks();
-                for (StackBoxInfo stackBoxInfo : stackBoxInfos) {
-                    addStackInfoToStackBoxInfo(stackBoxInfo, stackInfos);
-                    if (stackBoxInfo.stackBoxId == stackBoxId) {
-                        info = stackBoxInfo;
-                    }
-                }
+                return mStackSupervisor.getAllStackInfosLocked();
             }
-            return info;
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
+    @Override
+    public StackInfo getStackInfo(int stackId) {
+        enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
+                "getStackInfo()");
+        long ident = Binder.clearCallingIdentity();
+        try {
+            synchronized (this) {
+                return mStackSupervisor.getStackInfoLocked(stackId);
+            }
         } finally {
             Binder.restoreCallingIdentity(ident);
         }
@@ -8082,11 +8008,11 @@
         }
     }
 
-    public static final void installSystemProviders() {
+    public final void installSystemProviders() {
         List<ProviderInfo> providers;
-        synchronized (mSelf) {
-            ProcessRecord app = mSelf.mProcessNames.get("system", Process.SYSTEM_UID);
-            providers = mSelf.generateApplicationProvidersLocked(app);
+        synchronized (this) {
+            ProcessRecord app = mProcessNames.get("system", Process.SYSTEM_UID);
+            providers = generateApplicationProvidersLocked(app);
             if (providers != null) {
                 for (int i=providers.size()-1; i>=0; i--) {
                     ProviderInfo pi = (ProviderInfo)providers.get(i);
@@ -8102,9 +8028,9 @@
             mSystemThread.installSystemProviders(providers);
         }
 
-        mSelf.mCoreSettingsObserver = new CoreSettingsObserver(mSelf);
+        mCoreSettingsObserver = new CoreSettingsObserver(this);
 
-        mSelf.mUsageStatsService.monitorPackages();
+        mUsageStatsService.monitorPackages();
     }
 
     /**
@@ -8269,13 +8195,7 @@
         return mSleeping || mShuttingDown;
     }
 
-    public void goingToSleep() {
-        if (checkCallingPermission(android.Manifest.permission.DEVICE_POWER)
-                != PackageManager.PERMISSION_GRANTED) {
-            throw new SecurityException("Requires permission "
-                    + android.Manifest.permission.DEVICE_POWER);
-        }
-
+    void goingToSleep() {
         synchronized(this) {
             mWentToSleep = true;
             updateEventDispatchingLocked();
@@ -8350,13 +8270,7 @@
         }
     }
 
-    public void wakingUp() {
-        if (checkCallingPermission(android.Manifest.permission.DEVICE_POWER)
-                != PackageManager.PERMISSION_GRANTED) {
-            throw new SecurityException("Requires permission "
-                    + android.Manifest.permission.DEVICE_POWER);
-        }
-
+    void wakingUp() {
         synchronized(this) {
             mWentToSleep = false;
             updateEventDispatchingLocked();
@@ -8466,7 +8380,7 @@
                 mDebugTransient = !persistent;
                 if (packageName != null) {
                     forceStopPackageLocked(packageName, -1, false, false, true, true,
-                            false, UserHandle.USER_ALL, "set debug app");
+                            UserHandle.USER_ALL, "set debug app");
                 }
             }
         } finally {
@@ -8815,6 +8729,8 @@
                 } catch (RemoteException e) {
                 }
             }
+
+            mSafeMode = true;
         }
     }
 
@@ -9076,25 +8992,6 @@
         }
     }
 
-    public final void startRunning(String pkg, String cls, String action,
-            String data) {
-        synchronized(this) {
-            if (mStartRunning) {
-                return;
-            }
-            mStartRunning = true;
-            mTopComponent = pkg != null && cls != null
-                    ? new ComponentName(pkg, cls) : null;
-            mTopAction = action != null ? action : Intent.ACTION_MAIN;
-            mTopData = data;
-            if (!mSystemReady) {
-                return;
-            }
-        }
-
-        systemReady(null);
-    }
-
     private void retrieveSettings() {
         final ContentResolver resolver = mContext.getContentResolver();
         String debugApp = Settings.Global.getString(
@@ -9307,9 +9204,6 @@
 
             mAppOpsService.systemReady();
             mSystemReady = true;
-            if (!mStartRunning) {
-                return;
-            }
         }
 
         ArrayList<ProcessRecord> procsToKill = null;
@@ -9347,7 +9241,7 @@
         synchronized(this) {
             // Make sure we have no pre-ready processes sitting around.
             
-            if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) {
+            if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL) {
                 ResolveInfo ri = mContext.getPackageManager()
                         .resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST),
                                 STOCK_PM_FLAGS);
@@ -9389,7 +9283,7 @@
         if (goingCallback != null) goingCallback.run();
         
         synchronized (this) {
-            if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
+            if (mFactoryTest != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
                 try {
                     List apps = AppGlobals.getPackageManager().
                         getPersistentApplications(STOCK_PM_FLAGS);
@@ -9522,10 +9416,6 @@
 
     private boolean handleAppCrashLocked(ProcessRecord app, String shortMsg, String longMsg,
             String stackTrace) {
-        if (mHeadless) {
-            Log.e(TAG, "handleAppCrashLocked: " + app.processName);
-            return false;
-        }
         long now = SystemClock.uptimeMillis();
 
         Long crashTime;
@@ -10993,8 +10883,7 @@
             }
             if (dumpAll) {
                 pw.println("  Total persistent processes: " + numPers);
-                pw.println("  mStartRunning=" + mStartRunning
-                        + " mProcessesReady=" + mProcessesReady
+                pw.println("  mProcessesReady=" + mProcessesReady
                         + " mSystemReady=" + mSystemReady);
                 pw.println("  mBooting=" + mBooting
                         + " mBooted=" + mBooted
@@ -12414,6 +12303,7 @@
             boolean restarting, boolean allowRestart, int index) {
         if (index >= 0) {
             removeLruProcessLocked(app);
+            ProcessList.remove(app.pid);
         }
 
         mProcessesToGc.remove(app);
@@ -13400,7 +13290,7 @@
                         String list[] = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
                         if (list != null && (list.length > 0)) {
                             for (String pkg : list) {
-                                forceStopPackageLocked(pkg, -1, false, true, true, false, false, userId,
+                                forceStopPackageLocked(pkg, -1, false, true, true, false, userId,
                                         "storage unmount");
                             }
                             sendPackageBroadcastLocked(
@@ -13412,13 +13302,10 @@
                         if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
                             boolean removed = Intent.ACTION_PACKAGE_REMOVED.equals(
                                     intent.getAction());
-                            boolean fullUninstall = removed &&
-                                    !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
                             if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
                                 forceStopPackageLocked(ssp, UserHandle.getAppId(
                                         intent.getIntExtra(Intent.EXTRA_UID, -1)), false, true, true,
-                                        false, fullUninstall, userId,
-                                        removed ? "pkg removed" : "pkg changed");
+                                        false, userId, removed ? "pkg removed" : "pkg changed");
                             }
                             if (removed) {
                                 sendPackageBroadcastLocked(IApplicationThread.PACKAGE_REMOVED,
@@ -13905,7 +13792,7 @@
 
             final long origId = Binder.clearCallingIdentity();
             // Instrumentation can kill and relaunch even persistent processes
-            forceStopPackageLocked(ii.targetPackage, -1, true, false, true, true, false, userId,
+            forceStopPackageLocked(ii.targetPackage, -1, true, false, true, true, userId,
                     "start instr");
             ProcessRecord app = addAppLocked(ai, false);
             app.instrumentationClass = className;
@@ -13973,7 +13860,7 @@
         app.instrumentationProfileFile = null;
         app.instrumentationArguments = null;
 
-        forceStopPackageLocked(app.info.packageName, -1, false, false, true, true, false, app.userId,
+        forceStopPackageLocked(app.info.packageName, -1, false, false, true, true, app.userId,
                 "finished inst");
     }
 
@@ -14081,9 +13968,6 @@
      */
     boolean updateConfigurationLocked(Configuration values,
             ActivityRecord starting, boolean persistent, boolean initLocale) {
-        // do nothing if we are headless
-        if (mHeadless) return true;
-
         int changes = 0;
 
         if (values != null) {
@@ -14166,18 +14050,21 @@
 
         boolean kept = true;
         final ActivityStack mainStack = mStackSupervisor.getFocusedStack();
-        if (changes != 0 && starting == null) {
-            // If the configuration changed, and the caller is not already
-            // in the process of starting an activity, then find the top
-            // activity to check if its configuration needs to change.
-            starting = mainStack.topRunningActivityLocked(null);
-        }
+        // mainStack is null during startup.
+        if (mainStack != null) {
+            if (changes != 0 && starting == null) {
+                // If the configuration changed, and the caller is not already
+                // in the process of starting an activity, then find the top
+                // activity to check if its configuration needs to change.
+                starting = mainStack.topRunningActivityLocked(null);
+            }
 
-        if (starting != null) {
-            kept = mainStack.ensureActivityConfigurationLocked(starting, changes);
-            // And we need to make sure at this point that all other activities
-            // are made visible with the correct configuration.
-            mStackSupervisor.ensureActivitiesVisibleLocked(starting, changes);
+            if (starting != null) {
+                kept = mainStack.ensureActivityConfigurationLocked(starting, changes);
+                // And we need to make sure at this point that all other activities
+                // are made visible with the correct configuration.
+                mStackSupervisor.ensureActivitiesVisibleLocked(starting, changes);
+            }
         }
 
         if (values != null && mWindowManager != null) {
@@ -15289,16 +15176,13 @@
         }
 
         if (app.curAdj != app.setAdj) {
-            if (Process.setOomAdj(app.pid, app.curAdj)) {
-                if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(
-                    TAG, "Set " + app.pid + " " + app.processName +
-                    " adj " + app.curAdj + ": " + app.adjType);
-                app.setAdj = app.curAdj;
-            } else {
-                success = false;
-                Slog.w(TAG, "Failed setting oom adj of " + app + " to " + app.curAdj);
-            }
+            ProcessList.setOomAdj(app.pid, app.curAdj);
+            if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(
+                TAG, "Set " + app.pid + " " + app.processName +
+                " adj " + app.curAdj + ": " + app.adjType);
+            app.setAdj = app.curAdj;
         }
+
         if (app.setSchedGroup != app.curSchedGroup) {
             app.setSchedGroup = app.curSchedGroup;
             if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG,
@@ -16653,4 +16537,16 @@
         info.applicationInfo = getAppInfoForUser(info.applicationInfo, userId);
         return info;
     }
+
+    private final class LocalService extends ActivityManagerInternal {
+        @Override
+        public void goingToSleep() {
+            ActivityManagerService.this.goingToSleep();
+        }
+
+        @Override
+        public void wakingUp() {
+            ActivityManagerService.this.wakingUp();
+        }
+    }
 }
diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
similarity index 98%
rename from services/java/com/android/server/am/ActivityRecord.java
rename to services/core/java/com/android/server/am/ActivityRecord.java
index 63a52e6..37ead27 100755
--- a/services/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -21,6 +21,7 @@
 import com.android.internal.app.ResolverActivity;
 import com.android.server.AttributeCache;
 import com.android.server.am.ActivityStack.ActivityState;
+import com.android.server.am.ActivityStackSupervisor.ActivityContainer;
 
 import android.app.ActivityOptions;
 import android.app.ResultInfo;
@@ -138,11 +139,13 @@
     boolean forceNewConfig; // force re-create with new config next time
     int launchCount;        // count of launches since last state
     long lastLaunchTime;    // time of last lauch of this activity
+    ArrayList<ActivityContainer> mChildContainers = new ArrayList<ActivityContainer>();
 
     String stringName;      // for caching of toString().
 
     private boolean inHistory;  // are we in the history stack?
     final ActivityStackSupervisor mStackSupervisor;
+    ActivityContainer mInitialActivityContainer;
 
     void dump(PrintWriter pw, String prefix) {
         final long now = SystemClock.uptimeMillis();
@@ -347,7 +350,8 @@
             int _launchedFromUid, String _launchedFromPackage, Intent _intent, String _resolvedType,
             ActivityInfo aInfo, Configuration _configuration,
             ActivityRecord _resultTo, String _resultWho, int _reqCode,
-            boolean _componentSpecified, ActivityStackSupervisor supervisor) {
+            boolean _componentSpecified, ActivityStackSupervisor supervisor,
+            ActivityContainer container) {
         service = _service;
         appToken = new Token(this);
         info = aInfo;
@@ -378,6 +382,7 @@
         idle = false;
         hasBeenLaunched = false;
         mStackSupervisor = supervisor;
+        mInitialActivityContainer = container;
 
         // This starts out true, since the initial state of an activity
         // is that we have everything, and we shouldn't never consider it
@@ -481,7 +486,7 @@
     void setTask(TaskRecord newTask, ThumbnailHolder newThumbHolder, boolean isRoot) {
         if (task != null && task.removeActivity(this)) {
             if (task != newTask) {
-                mStackSupervisor.removeTask(task);
+                task.stack.removeTask(task);
             } else {
                 Slog.d(TAG, "!!! REMOVE THIS LOG !!! setTask: nearly removed stack=" +
                         (newTask == null ? null : newTask.stack));
diff --git a/services/java/com/android/server/am/ActivityResult.java b/services/core/java/com/android/server/am/ActivityResult.java
similarity index 100%
rename from services/java/com/android/server/am/ActivityResult.java
rename to services/core/java/com/android/server/am/ActivityResult.java
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
similarity index 96%
rename from services/java/com/android/server/am/ActivityStack.java
rename to services/core/java/com/android/server/am/ActivityStack.java
index 4d6727c..c6cd312 100755
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -36,9 +36,12 @@
 import static com.android.server.am.ActivityStackSupervisor.DEBUG_STATES;
 import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID;
 
+import static com.android.server.am.ActivityStackSupervisor.ActivityContainer.CONTAINER_STATE_HAS_SURFACE;
+
 import com.android.internal.os.BatteryStatsImpl;
 import com.android.server.Watchdog;
 import com.android.server.am.ActivityManagerService.ItemMatcher;
+import com.android.server.am.ActivityStackSupervisor.ActivityContainer;
 import com.android.server.wm.AppTransition;
 import com.android.server.wm.TaskGroup;
 import com.android.server.wm.WindowManagerService;
@@ -52,7 +55,6 @@
 import android.app.ResultInfo;
 import android.app.ActivityManager.RunningTaskInfo;
 import android.content.ComponentName;
-import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManager;
@@ -139,8 +141,6 @@
     final ActivityManagerService mService;
     final WindowManagerService mWindowManager;
 
-    final Context mContext;
-
     /**
      * The back history of all previous (and possibly still
      * running) activities.  It contains #TaskRecord objects.
@@ -229,6 +229,11 @@
     int mCurrentUser;
 
     final int mStackId;
+    final ActivityContainer mActivityContainer;
+    /** The other stacks, in order, on the attached display. Updated at attach/detach time. */
+    ArrayList<ActivityStack> mStacks;
+    /** The attached Display's unique identifier, or -1 if detached */
+    int mDisplayId;
 
     /** Run all ActivityStacks through this */
     final ActivityStackSupervisor mStackSupervisor;
@@ -319,7 +324,7 @@
         }
     }
 
-    private int numActivities() {
+    int numActivities() {
         int count = 0;
         for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
             count += mTaskHistory.get(taskNdx).mActivities.size();
@@ -327,14 +332,14 @@
         return count;
     }
 
-    ActivityStack(ActivityManagerService service, Context context, Looper looper, int stackId) {
-        mHandler = new ActivityStackHandler(looper);
-        mService = service;
-        mWindowManager = service.mWindowManager;
-        mStackSupervisor = service.mStackSupervisor;
-        mContext = context;
-        mStackId = stackId;
-        mCurrentUser = service.mCurrentUserId;
+    ActivityStack(ActivityStackSupervisor.ActivityContainer activityContainer) {
+        mActivityContainer = activityContainer;
+        mStackSupervisor = activityContainer.getOuter();
+        mService = mStackSupervisor.mService;
+        mHandler = new ActivityStackHandler(mService.mHandler.getLooper());
+        mWindowManager = mService.mWindowManager;
+        mStackId = activityContainer.mStackId;
+        mCurrentUser = mService.mCurrentUserId;
     }
 
     boolean okToShow(ActivityRecord r) {
@@ -436,25 +441,6 @@
         return null;
     }
 
-    boolean containsApp(ProcessRecord app) {
-        if (app == null) {
-            return false;
-        }
-        for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
-            final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;
-            for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
-                final ActivityRecord r = activities.get(activityNdx);
-                if (r.finishing) {
-                    continue;
-                }
-                if (r.app == app) {
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-
     final boolean updateLRUListLocked(ActivityRecord r) {
         final boolean hadit = mLRUActivities.remove(r);
         mLRUActivities.add(r);
@@ -465,6 +451,25 @@
         return mStackId == HOME_STACK_ID;
     }
 
+    final boolean isOnHomeDisplay() {
+        return isAttached() &&
+                mActivityContainer.mActivityDisplay.mDisplayId == Display.DEFAULT_DISPLAY;
+    }
+
+    final void moveToFront() {
+        if (isAttached()) {
+            if (isOnHomeDisplay()) {
+                mStackSupervisor.moveHomeStack(isHomeStack());
+            }
+            mStacks.remove(this);
+            mStacks.add(this);
+        }
+    }
+
+    final boolean isAttached() {
+        return mStacks != null;
+    }
+
     /**
      * Returns the top activity in any existing task matching the given
      * Intent.  Returns null if no such task is found.
@@ -733,6 +738,12 @@
             mStackSupervisor.resumeTopActivitiesLocked();
             return;
         }
+
+        if (mActivityContainer.mParentActivity == null) {
+            // Top level stack, not a child. Look for child stacks.
+            mStackSupervisor.pauseChildStacks(prev, userLeaving, uiSleeping);
+        }
+
         if (DEBUG_STATES) Slog.v(TAG, "Moving to PAUSING: " + prev);
         else if (DEBUG_PAUSE) Slog.v(TAG, "Start pausing: " + prev);
         mResumedActivity = null;
@@ -1016,6 +1027,16 @@
         return mStackSupervisor.isFrontStack(this);
     }
 
+    private void setVisibile(ActivityRecord r, boolean visible) {
+        r.visible = visible;
+        mWindowManager.setAppVisibility(r.appToken, visible);
+        final ArrayList<ActivityContainer> containers = r.mChildContainers;
+        for (int containerNdx = containers.size() - 1; containerNdx >= 0; --containerNdx) {
+            ActivityContainer container = containers.get(containerNdx);
+            container.setVisible(visible);
+        }
+    }
+
     /**
      * Version of ensureActivitiesVisible that can easily be called anywhere.
      */
@@ -1094,8 +1115,7 @@
                             if (!r.visible) {
                                 if (DEBUG_VISBILITY) Slog.v(
                                         TAG, "Starting and making visible: " + r);
-                                r.visible = true;
-                                mWindowManager.setAppVisibility(r.appToken, true);
+                                setVisibile(r, true);
                             }
                             if (r != starting) {
                                 mStackSupervisor.startSpecificActivityLocked(r, false, false);
@@ -1121,7 +1141,7 @@
                                 if (mTranslucentActivityWaiting != null) {
                                     mUndrawnActivitiesBelowTopTranslucent.add(r);
                                 }
-                                mWindowManager.setAppVisibility(r.appToken, true);
+                                setVisibile(r, true);
                                 r.sleeping = false;
                                 r.app.pendingUiClean = true;
                                 r.app.thread.scheduleWindowVisibility(r.appToken, true);
@@ -1157,9 +1177,8 @@
                     // sure they no longer are keeping the screen frozen.
                     if (r.visible) {
                         if (DEBUG_VISBILITY) Slog.v(TAG, "Making invisible: " + r);
-                        r.visible = false;
                         try {
-                            mWindowManager.setAppVisibility(r.appToken, false);
+                            setVisibile(r, false);
                             switch (r.state) {
                                 case STOPPING:
                                 case STOPPED:
@@ -1215,6 +1234,7 @@
      * occurred and the activity will be notified immediately.
      */
     void notifyActivityDrawnLocked(ActivityRecord r) {
+        mActivityContainer.setDrawn();
         if ((r == null)
                 || (mUndrawnActivitiesBelowTopTranslucent.remove(r) &&
                         mUndrawnActivitiesBelowTopTranslucent.isEmpty())) {
@@ -1225,12 +1245,14 @@
             mUndrawnActivitiesBelowTopTranslucent.clear();
             mHandler.removeMessages(TRANSLUCENT_TIMEOUT_MSG);
 
-            if (waitingActivity != null && waitingActivity.app != null &&
-                    waitingActivity.app.thread != null) {
-                try {
-                    waitingActivity.app.thread.scheduleTranslucentConversionComplete(
-                            waitingActivity.appToken, r != null);
-                } catch (RemoteException e) {
+            if (waitingActivity != null) {
+                mWindowManager.setWindowOpaque(waitingActivity.appToken, false);
+                if (waitingActivity.app != null && waitingActivity.app.thread != null) {
+                    try {
+                        waitingActivity.app.thread.scheduleTranslucentConversionComplete(
+                                waitingActivity.appToken, r != null);
+                    } catch (RemoteException e) {
+                    }
                 }
             }
         }
@@ -1252,6 +1274,14 @@
     final boolean resumeTopActivityLocked(ActivityRecord prev, Bundle options) {
         if (ActivityManagerService.DEBUG_LOCKSCREEN) mService.logLockScreen("");
 
+        ActivityRecord parent = mActivityContainer.mParentActivity;
+        if ((parent != null && parent.state != ActivityState.RESUMED) ||
+                !mActivityContainer.isAttached()) {
+            // Do not resume this stack if its parent is not resumed.
+            // TODO: If in a loop, make sure that parent stack resumeTopActivity is called 1st.
+            return false;
+        }
+
         // Find the first activity that is not finishing.
         ActivityRecord next = topRunningActivityLocked(null);
 
@@ -1266,7 +1296,8 @@
             ActivityOptions.abort(options);
             if (DEBUG_STATES) Slog.d(TAG, "resumeTopActivityLocked: No more activities go home");
             if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
-            return mStackSupervisor.resumeHomeActivity(prev);
+            // Only resume home if on home display
+            return isOnHomeDisplay() && mStackSupervisor.resumeHomeActivity(prev);
         }
 
         next.delayedResume = false;
@@ -1296,8 +1327,10 @@
                 final int taskNdx = mTaskHistory.indexOf(prevTask) + 1;
                 mTaskHistory.get(taskNdx).mOnTopOfHome = true;
             } else {
-                if (DEBUG_STATES) Slog.d(TAG, "resumeTopActivityLocked: Launching home next");
-                return mStackSupervisor.resumeHomeActivity(prev);
+                if (DEBUG_STATES && isOnHomeDisplay()) Slog.d(TAG,
+                        "resumeTopActivityLocked: Launching home next");
+                // Only resume home if on home display
+                return isOnHomeDisplay() && mStackSupervisor.resumeHomeActivity(prev);
             }
         }
 
@@ -1659,10 +1692,14 @@
     private void insertTaskAtTop(TaskRecord task) {
         // If this is being moved to the top by another activity or being launched from the home
         // activity, set mOnTopOfHome accordingly.
-        ActivityStack lastStack = mStackSupervisor.getLastStack();
-        final boolean fromHome = lastStack == null ? true : lastStack.isHomeStack();
-        if (!isHomeStack() && (fromHome || topTask() != task)) {
-            task.mOnTopOfHome = fromHome;
+        if (isOnHomeDisplay()) {
+            ActivityStack lastStack = mStackSupervisor.getLastStack();
+            final boolean fromHome = lastStack.isHomeStack();
+            if (!isHomeStack() && (fromHome || topTask() != task)) {
+                task.mOnTopOfHome = fromHome;
+            }
+        } else {
+            task.mOnTopOfHome = false;
         }
 
         mTaskHistory.remove(task);
@@ -2520,6 +2557,20 @@
         return r;
     }
 
+    void finishAllActivitiesLocked() {
+        for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
+            final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;
+            for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
+                final ActivityRecord r = activities.get(activityNdx);
+                if (r.finishing) {
+                    continue;
+                }
+                Slog.d(TAG, "finishAllActivitiesLocked: finishing " + r);
+                finishCurrentActivityLocked(r, FINISH_IMMEDIATELY, false);
+            }
+        }
+    }
+
     final boolean navigateUpToLocked(IBinder token, Intent destIntent, int resultCode,
             Intent resultData) {
         final ActivityRecord srec = ActivityRecord.forToken(token);
@@ -2588,7 +2639,7 @@
                     int res = mStackSupervisor.startActivityLocked(srec.app.thread, destIntent,
                             null, aInfo, parent.appToken, null,
                             0, -1, parent.launchedFromUid, parent.launchedFromPackage,
-                            0, null, true, null);
+                            0, null, true, null, null);
                     foundParentInTask = res == ActivityManager.START_SUCCESS;
                 } catch (RemoteException e) {
                     foundParentInTask = false;
@@ -2669,7 +2720,8 @@
         r.finishLaunchTickingLocked();
     }
 
-    final void removeActivityFromHistoryLocked(ActivityRecord r) {
+    private void removeActivityFromHistoryLocked(ActivityRecord r) {
+        mStackSupervisor.removeChildActivityContainers(r);
         finishActivityResultsLocked(r, Activity.RESULT_CANCELED, null);
         r.makeFinishing();
         if (DEBUG_ADD_REMOVE) {
@@ -2677,15 +2729,6 @@
             here.fillInStackTrace();
             Slog.i(TAG, "Removing activity " + r + " from stack");
         }
-        final TaskRecord task = r.task;
-        if (task != null && task.removeActivity(r)) {
-            if (DEBUG_STACK) Slog.i(TAG,
-                    "removeActivityFromHistoryLocked: last activity removed from " + this);
-            if (mStackSupervisor.isFrontStack(this) && task == topTask() && task.mOnTopOfHome) {
-                mStackSupervisor.moveHomeToTop();
-            }
-            mStackSupervisor.removeTask(task);
-        }
         r.takeFromHistory();
         removeTimeoutsForActivityLocked(r);
         if (DEBUG_STATES) Slog.v(TAG, "Moving to DESTROYED: " + r + " (removed from history)");
@@ -2696,6 +2739,15 @@
         if (VALIDATE_TOKENS) {
             validateAppTokensLocked();
         }
+        final TaskRecord task = r.task;
+        if (task != null && task.removeActivity(r)) {
+            if (DEBUG_STACK) Slog.i(TAG,
+                    "removeActivityFromHistoryLocked: last activity removed from " + this);
+            if (mStackSupervisor.isFrontStack(this) && task == topTask() && task.mOnTopOfHome) {
+                mStackSupervisor.moveHomeToTop();
+            }
+            removeTask(task);
+        }
         cleanUpActivityServicesLocked(r);
         r.removeUriPermissionsLocked();
     }
@@ -2757,7 +2809,6 @@
         }
         if (activityRemoved) {
             mStackSupervisor.resumeTopActivitiesLocked();
-
         }
     }
 
@@ -3043,7 +3094,7 @@
             return;
         }
 
-        mStackSupervisor.moveHomeStack(isHomeStack());
+        moveToFront();
 
         // Shift all activities with this task up to the top
         // of the stack, keeping them in the same internal order.
@@ -3152,7 +3203,7 @@
         }
 
         final TaskRecord task = mResumedActivity != null ? mResumedActivity.task : null;
-        if (task == tr && task.mOnTopOfHome || numTasks <= 1) {
+        if (task == tr && tr.mOnTopOfHome || numTasks <= 1 && isOnHomeDisplay()) {
             tr.mOnTopOfHome = false;
             return mStackSupervisor.resumeHomeActivity(null);
         }
@@ -3313,6 +3364,8 @@
 
         r.startFreezingScreenLocked(r.app, 0);
 
+        mStackSupervisor.removeChildActivityContainers(r);
+
         try {
             if (DEBUG_SWITCH || DEBUG_STATES) Slog.i(TAG,
                     (andResume ? "Relaunching to RESUMED " : "Relaunching to PAUSED ")
@@ -3345,14 +3398,20 @@
             for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
                 final ActivityRecord r = activities.get(activityNdx);
                 if (r.appToken == token) {
-                        return true;
+                    return true;
                 }
                 if (r.fullscreen && !r.finishing) {
                     return false;
                 }
             }
         }
-        return true;
+        final ActivityRecord r = ActivityRecord.forToken(token);
+        if (r == null) {
+            return false;
+        }
+        if (r.finishing) Slog.e(TAG, "willActivityBeVisibleLocked: Returning false,"
+                + " would have returned true for r=" + r);
+        return !r.finishing;
     }
 
     void closeSystemDialogsLocked() {
@@ -3591,14 +3650,30 @@
         return starting;
     }
 
-    boolean removeTask(TaskRecord task) {
+    void removeTask(TaskRecord task) {
+        mWindowManager.removeTask(task.taskId);
+        final ActivityRecord r = mResumedActivity;
+        if (r != null && r.task == task) {
+            mResumedActivity = null;
+        }
+
         final int taskNdx = mTaskHistory.indexOf(task);
         final int topTaskNdx = mTaskHistory.size() - 1;
         if (task.mOnTopOfHome && taskNdx < topTaskNdx) {
             mTaskHistory.get(taskNdx + 1).mOnTopOfHome = true;
         }
         mTaskHistory.remove(task);
-        return mTaskHistory.isEmpty();
+
+        if (mTaskHistory.isEmpty()) {
+            if (DEBUG_STACK) Slog.i(TAG, "removeTask: moving to back stack=" + this);
+            if (isOnHomeDisplay()) {
+                mStackSupervisor.moveHomeStack(!isHomeStack());
+            }
+            if (mStacks != null) {
+                mStacks.remove(this);
+                mStacks.add(0, this);
+            }
+        }
     }
 
     TaskRecord createTaskRecord(int taskId, ActivityInfo info, Intent intent, boolean toTop) {
diff --git a/services/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
similarity index 67%
rename from services/java/com/android/server/am/ActivityStackSupervisor.java
rename to services/core/java/com/android/server/am/ActivityStackSupervisor.java
index d616f1b..e942afb 100644
--- a/services/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -34,8 +34,11 @@
 
 import android.app.Activity;
 import android.app.ActivityManager;
+import android.app.ActivityManager.StackInfo;
 import android.app.ActivityOptions;
 import android.app.AppGlobals;
+import android.app.IActivityContainer;
+import android.app.IActivityContainerCallback;
 import android.app.IActivityManager;
 import android.app.IApplicationThread;
 import android.app.IThumbnailReceiver;
@@ -53,6 +56,13 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.res.Configuration;
+import android.graphics.Point;
+import android.hardware.display.DisplayManager;
+import android.hardware.display.DisplayManager.DisplayListener;
+import android.hardware.display.DisplayManagerGlobal;
+import android.hardware.display.VirtualDisplay;
+import android.hardware.input.InputManager;
+import android.hardware.input.InputManagerInternal;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Debug;
@@ -68,13 +78,18 @@
 import android.os.UserHandle;
 import android.util.EventLog;
 import android.util.Slog;
-import android.util.SparseIntArray;
+import android.util.SparseArray;
 
+import android.util.SparseIntArray;
+import android.view.Display;
+import android.view.DisplayInfo;
+import android.view.InputEvent;
+import android.view.Surface;
 import com.android.internal.app.HeavyWeightSwitcherActivity;
 import com.android.internal.os.TransferPipe;
+import com.android.server.LocalServices;
 import com.android.server.am.ActivityManagerService.PendingActivityLaunch;
 import com.android.server.am.ActivityStack.ActivityState;
-import com.android.server.wm.StackBox;
 import com.android.server.wm.WindowManagerService;
 
 import java.io.FileDescriptor;
@@ -83,7 +98,7 @@
 import java.util.ArrayList;
 import java.util.List;
 
-public final class ActivityStackSupervisor {
+public final class ActivityStackSupervisor implements DisplayListener {
     static final boolean DEBUG = ActivityManagerService.DEBUG || false;
     static final boolean DEBUG_ADD_REMOVE = DEBUG || false;
     static final boolean DEBUG_APP = DEBUG || false;
@@ -107,19 +122,24 @@
     static final int RESUME_TOP_ACTIVITY_MSG = FIRST_SUPERVISOR_STACK_MSG + 2;
     static final int SLEEP_TIMEOUT_MSG = FIRST_SUPERVISOR_STACK_MSG + 3;
     static final int LAUNCH_TIMEOUT_MSG = FIRST_SUPERVISOR_STACK_MSG + 4;
+    static final int HANDLE_DISPLAY_ADDED = FIRST_SUPERVISOR_STACK_MSG + 5;
+    static final int HANDLE_DISPLAY_CHANGED = FIRST_SUPERVISOR_STACK_MSG + 6;
+    static final int HANDLE_DISPLAY_REMOVED = FIRST_SUPERVISOR_STACK_MSG + 7;
+    static final int CONTAINER_CALLBACK_VISIBILITY = FIRST_SUPERVISOR_STACK_MSG + 8;
+
+    private final static String VIRTUAL_DISPLAY_BASE_NAME = "ActivityViewVirtualDisplay";
 
     // For debugging to make sure the caller when acquiring/releasing our
     // wake lock is the system process.
     static final boolean VALIDATE_WAKE_LOCK_CALLER = false;
 
     final ActivityManagerService mService;
-    final Context mContext;
-    final Looper mLooper;
 
     final ActivityStackSupervisorHandler mHandler;
 
     /** Short cut */
     WindowManagerService mWindowManager;
+    DisplayManager mDisplayManager;
 
     /** Dismiss the keyguard after the next activity is displayed? */
     boolean mDismissKeyguardOnNextActivity = false;
@@ -134,22 +154,17 @@
     /** The current user */
     private int mCurrentUser;
 
-    /** The stack containing the launcher app */
+    /** The stack containing the launcher app. Assumed to always be attached to
+     * Display.DEFAULT_DISPLAY. */
     private ActivityStack mHomeStack;
 
-    /** The non-home stack currently receiving input or launching the next activity. If home is
-     * in front then mHomeStack overrides mFocusedStack.
-     * DO NOT ACCESS DIRECTLY - It may be null, use getFocusedStack() */
+    /** The stack currently receiving input or launching the next activity. */
     private ActivityStack mFocusedStack;
 
-    /** All the non-launcher stacks */
-    private ArrayList<ActivityStack> mStacks = new ArrayList<ActivityStack>();
-
-    private static final int STACK_STATE_HOME_IN_FRONT = 0;
-    private static final int STACK_STATE_HOME_TO_BACK = 1;
-    private static final int STACK_STATE_HOME_IN_BACK = 2;
-    private static final int STACK_STATE_HOME_TO_FRONT = 3;
-    private int mStackState = STACK_STATE_HOME_IN_FRONT;
+    /** If this is the same as mFocusedStack then the activity on the top of the focused stack has
+     * been resumed. If stacks are changing position this will hold the old stack until the new
+     * stack becomes resumed after which it will be set to mFocusedStack. */
+    private ActivityStack mLastFocusedStack;
 
     /** List of activities that are waiting for a new activity to become visible before completing
      * whatever operation they are supposed to do. */
@@ -206,14 +221,21 @@
     /** Stack id of the front stack when user switched, indexed by userId. */
     SparseIntArray mUserStackInFront = new SparseIntArray(2);
 
-    public ActivityStackSupervisor(ActivityManagerService service, Context context,
-            Looper looper) {
+    // TODO: Add listener for removal of references.
+    /** Mapping from (ActivityStack/TaskStack).mStackId to their current state */
+    SparseArray<ActivityContainer> mActivityContainers = new SparseArray<ActivityContainer>();
+
+    /** Mapping from displayId to display current state */
+    private final SparseArray<ActivityDisplay> mActivityDisplays =
+            new SparseArray<ActivityDisplay>();
+
+    InputManagerInternal mInputManagerInternal;
+
+    public ActivityStackSupervisor(ActivityManagerService service) {
         mService = service;
-        mContext = context;
-        mLooper = looper;
-        PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
+        PowerManager pm = (PowerManager)mService.mContext.getSystemService(Context.POWER_SERVICE);
         mGoingToSleep = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Sleep");
-        mHandler = new ActivityStackSupervisorHandler(looper);
+        mHandler = new ActivityStackSupervisorHandler(mService.mHandler.getLooper());
         if (VALIDATE_WAKE_LOCK_CALLER && Binder.getCallingUid() != Process.myUid()) {
             throw new IllegalStateException("Calling must be system uid");
         }
@@ -223,9 +245,25 @@
     }
 
     void setWindowManager(WindowManagerService wm) {
-        mWindowManager = wm;
-        mHomeStack = new ActivityStack(mService, mContext, mLooper, HOME_STACK_ID);
-        mStacks.add(mHomeStack);
+        synchronized (mService) {
+            mWindowManager = wm;
+
+            mDisplayManager =
+                    (DisplayManager)mService.mContext.getSystemService(Context.DISPLAY_SERVICE);
+            mDisplayManager.registerDisplayListener(this, null);
+
+            Display[] displays = mDisplayManager.getDisplays();
+            for (int displayNdx = displays.length - 1; displayNdx >= 0; --displayNdx) {
+                final int displayId = displays[displayNdx].getDisplayId();
+                ActivityDisplay activityDisplay = new ActivityDisplay(displayId);
+                mActivityDisplays.put(displayId, activityDisplay);
+            }
+
+            createStackOnDisplay(HOME_STACK_ID, Display.DEFAULT_DISPLAY);
+            mHomeStack = mFocusedStack = mLastFocusedStack = getStack(HOME_STACK_ID);
+
+            mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
+        }
     }
 
     void dismissKeyguard() {
@@ -237,43 +275,42 @@
     }
 
     ActivityStack getFocusedStack() {
-        if (mFocusedStack == null) {
-            return mHomeStack;
-        }
-        switch (mStackState) {
-            case STACK_STATE_HOME_IN_FRONT:
-            case STACK_STATE_HOME_TO_FRONT:
-                return mHomeStack;
-            case STACK_STATE_HOME_IN_BACK:
-            case STACK_STATE_HOME_TO_BACK:
-            default:
-                return mFocusedStack;
-        }
+        return mFocusedStack;
     }
 
     ActivityStack getLastStack() {
-        switch (mStackState) {
-            case STACK_STATE_HOME_IN_FRONT:
-            case STACK_STATE_HOME_TO_BACK:
-                return mHomeStack;
-            case STACK_STATE_HOME_TO_FRONT:
-            case STACK_STATE_HOME_IN_BACK:
-            default:
-                return mFocusedStack;
-        }
+        return mLastFocusedStack;
     }
 
+    // TODO: Split into two methods isFrontStack for any visible stack and isFrontmostStack for the
+    // top of all visible stacks.
     boolean isFrontStack(ActivityStack stack) {
-        return !(stack.isHomeStack() ^ getFocusedStack().isHomeStack());
+        final ActivityRecord parent = stack.mActivityContainer.mParentActivity;
+        if (parent != null) {
+            stack = parent.task.stack;
+        }
+        ArrayList<ActivityStack> stacks = stack.mStacks;
+        if (stacks != null && !stacks.isEmpty()) {
+            return stack == stacks.get(stacks.size() - 1);
+        }
+        return false;
     }
 
     void moveHomeStack(boolean toFront) {
-        final boolean homeInFront = isFrontStack(mHomeStack);
-        if (homeInFront ^ toFront) {
-            if (DEBUG_STACK) Slog.d(TAG, "moveHomeTask: mStackState old=" +
-                    stackStateToString(mStackState) + " new=" + stackStateToString(homeInFront ?
-                    STACK_STATE_HOME_TO_BACK : STACK_STATE_HOME_TO_FRONT));
-            mStackState = homeInFront ? STACK_STATE_HOME_TO_BACK : STACK_STATE_HOME_TO_FRONT;
+        ArrayList<ActivityStack> stacks = mHomeStack.mStacks;
+        int topNdx = stacks.size() - 1;
+        if (topNdx <= 0) {
+            return;
+        }
+        ActivityStack topStack = stacks.get(topNdx);
+        final boolean homeInFront = topStack == mHomeStack;
+        if (homeInFront != toFront) {
+            mLastFocusedStack = topStack;
+            stacks.remove(mHomeStack);
+            stacks.add(toFront ? topNdx : 0, mHomeStack);
+            mFocusedStack = stacks.get(topNdx);
+            if (DEBUG_STACK) Slog.d(TAG, "moveHomeTask: topStack old=" + topStack + " new="
+                    + mFocusedStack);
         }
     }
 
@@ -301,21 +338,29 @@
     }
 
     TaskRecord anyTaskForIdLocked(int id) {
-        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
-            ActivityStack stack = mStacks.get(stackNdx);
-            TaskRecord task = stack.taskForIdLocked(id);
-            if (task != null) {
-                return task;
+        int numDisplays = mActivityDisplays.size();
+        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
+            ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
+            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+                ActivityStack stack = stacks.get(stackNdx);
+                TaskRecord task = stack.taskForIdLocked(id);
+                if (task != null) {
+                    return task;
+                }
             }
         }
         return null;
     }
 
     ActivityRecord isInAnyStackLocked(IBinder token) {
-        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
-            final ActivityRecord r = mStacks.get(stackNdx).isInStackLocked(token);
-            if (r != null) {
-                return r;
+        int numDisplays = mActivityDisplays.size();
+        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
+            ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
+            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityRecord r = stacks.get(stackNdx).isInStackLocked(token);
+                if (r != null) {
+                    return r;
+                }
             }
         }
         return null;
@@ -331,26 +376,6 @@
         return mCurTaskId;
     }
 
-    void removeTask(TaskRecord task) {
-        mWindowManager.removeTask(task.taskId);
-        final ActivityStack stack = task.stack;
-        final ActivityRecord r = stack.mResumedActivity;
-        if (r != null && r.task == task) {
-            stack.mResumedActivity = null;
-        }
-        if (stack.removeTask(task) && !stack.isHomeStack()) {
-            if (DEBUG_STACK) Slog.i(TAG, "removeTask: removing stack " + stack);
-            mStacks.remove(stack);
-            final int stackId = stack.mStackId;
-            final int nextStackId = mWindowManager.removeStack(stackId);
-            // TODO: Perhaps we need to let the ActivityManager determine the next focus...
-            if (mFocusedStack == null || mFocusedStack.mStackId == stackId) {
-                // If this is the last app stack, set mFocusedStack to null.
-                mFocusedStack = nextStackId == HOME_STACK_ID ? null : getStack(nextStackId);
-            }
-        }
-    }
-
     ActivityRecord resumedAppLocked() {
         ActivityStack stack = getFocusedStack();
         if (stack == null) {
@@ -366,29 +391,29 @@
         return resumedActivity;
     }
 
-    boolean attachApplicationLocked(ProcessRecord app, boolean headless) throws Exception {
-        boolean didSomething = false;
+    boolean attachApplicationLocked(ProcessRecord app) throws Exception {
         final String processName = app.processName;
-        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
-            final ActivityStack stack = mStacks.get(stackNdx);
-            if (!isFrontStack(stack)) {
-                continue;
-            }
-            ActivityRecord hr = stack.topRunningActivityLocked(null);
-            if (hr != null) {
-                if (hr.app == null && app.uid == hr.info.applicationInfo.uid
-                        && processName.equals(hr.processName)) {
-                    try {
-                        if (headless) {
-                            Slog.e(TAG, "Starting activities not supported on headless device: "
-                                    + hr);
-                        } else if (realStartActivityLocked(hr, app, true, true)) {
-                            didSomething = true;
+        boolean didSomething = false;
+        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
+            ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
+            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = stacks.get(stackNdx);
+                if (!isFrontStack(stack)) {
+                    continue;
+                }
+                ActivityRecord hr = stack.topRunningActivityLocked(null);
+                if (hr != null) {
+                    if (hr.app == null && app.uid == hr.info.applicationInfo.uid
+                            && processName.equals(hr.processName)) {
+                        try {
+                            if (realStartActivityLocked(hr, app, true, true)) {
+                                didSomething = true;
+                            }
+                        } catch (Exception e) {
+                            Slog.w(TAG, "Exception in new application when starting activity "
+                                  + hr.intent.getComponent().flattenToShortString(), e);
+                            throw e;
                         }
-                    } catch (Exception e) {
-                        Slog.w(TAG, "Exception in new application when starting activity "
-                              + hr.intent.getComponent().flattenToShortString(), e);
-                        throw e;
                     }
                 }
             }
@@ -400,53 +425,54 @@
     }
 
     boolean allResumedActivitiesIdle() {
-        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
-            final ActivityStack stack = mStacks.get(stackNdx);
-            if (!isFrontStack(stack)) {
-                continue;
-            }
-            final ActivityRecord resumedActivity = stack.mResumedActivity;
-            if (resumedActivity == null || !resumedActivity.idle) {
-                return false;
+        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
+            ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
+            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = stacks.get(stackNdx);
+                if (!isFrontStack(stack) || stack.numActivities() == 0) {
+                    continue;
+                }
+                final ActivityRecord resumedActivity = stack.mResumedActivity;
+                if (resumedActivity == null || !resumedActivity.idle) {
+                    if (DEBUG_STATES) Slog.d(TAG, "allResumedActivitiesIdle: stack="
+                             + stack.mStackId + " " + resumedActivity + " not idle");
+                    return false;
+                }
             }
         }
         return true;
     }
 
     boolean allResumedActivitiesComplete() {
-        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
-            final ActivityStack stack = mStacks.get(stackNdx);
-            if (isFrontStack(stack)) {
-                final ActivityRecord r = stack.mResumedActivity;
-                if (r != null && r.state != ActivityState.RESUMED) {
-                    return false;
+        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
+            ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
+            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = stacks.get(stackNdx);
+                if (isFrontStack(stack)) {
+                    final ActivityRecord r = stack.mResumedActivity;
+                    if (r != null && r.state != ActivityState.RESUMED) {
+                        return false;
+                    }
                 }
             }
         }
         // TODO: Not sure if this should check if all Paused are complete too.
-        switch (mStackState) {
-            case STACK_STATE_HOME_TO_BACK:
-                if (DEBUG_STACK) Slog.d(TAG, "allResumedActivitiesComplete: mStackState old=" +
-                        stackStateToString(STACK_STATE_HOME_TO_BACK) + " new=" +
-                        stackStateToString(STACK_STATE_HOME_IN_BACK));
-                mStackState = STACK_STATE_HOME_IN_BACK;
-                break;
-            case STACK_STATE_HOME_TO_FRONT:
-                if (DEBUG_STACK) Slog.d(TAG, "allResumedActivitiesComplete: mStackState old=" +
-                        stackStateToString(STACK_STATE_HOME_TO_FRONT) + " new=" +
-                        stackStateToString(STACK_STATE_HOME_IN_FRONT));
-                mStackState = STACK_STATE_HOME_IN_FRONT;
-                break;
-        }
+        if (DEBUG_STACK) Slog.d(TAG,
+                "allResumedActivitiesComplete: mLastFocusedStack changing from=" +
+                mLastFocusedStack + " to=" + mFocusedStack);
+        mLastFocusedStack = mFocusedStack;
         return true;
     }
 
     boolean allResumedActivitiesVisible() {
-        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
-            final ActivityStack stack = mStacks.get(stackNdx);
-            final ActivityRecord r = stack.mResumedActivity;
-            if (r != null && (!r.nowVisible || r.waitingVisible)) {
-                return false;
+        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
+            ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
+            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = stacks.get(stackNdx);
+                final ActivityRecord r = stack.mResumedActivity;
+                if (r != null && (!r.nowVisible || r.waitingVisible)) {
+                    return false;
+                }
             }
         }
         return true;
@@ -459,13 +485,16 @@
      */
     boolean pauseBackStacks(boolean userLeaving) {
         boolean someActivityPaused = false;
-        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
-            final ActivityStack stack = mStacks.get(stackNdx);
-            if (!isFrontStack(stack) && stack.mResumedActivity != null) {
-                if (DEBUG_STATES) Slog.d(TAG, "pauseBackStacks: stack=" + stack +
-                        " mResumedActivity=" + stack.mResumedActivity);
-                stack.startPausingLocked(userLeaving, false);
-                someActivityPaused = true;
+        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
+            ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
+            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = stacks.get(stackNdx);
+                if (!isFrontStack(stack) && stack.mResumedActivity != null) {
+                    if (DEBUG_STATES) Slog.d(TAG, "pauseBackStacks: stack=" + stack +
+                            " mResumedActivity=" + stack.mResumedActivity);
+                    stack.startPausingLocked(userLeaving, false);
+                    someActivityPaused = true;
+                }
             }
         }
         return someActivityPaused;
@@ -473,23 +502,40 @@
 
     boolean allPausedActivitiesComplete() {
         boolean pausing = true;
-        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
-            final ActivityStack stack = mStacks.get(stackNdx);
-            final ActivityRecord r = stack.mPausingActivity;
-            if (r != null && r.state != ActivityState.PAUSED
-                    && r.state != ActivityState.STOPPED
-                    && r.state != ActivityState.STOPPING) {
-                if (DEBUG_STATES) {
-                    Slog.d(TAG, "allPausedActivitiesComplete: r=" + r + " state=" + r.state);
-                    pausing = false;
-                } else {
-                    return false;
+        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
+            ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
+            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = stacks.get(stackNdx);
+                final ActivityRecord r = stack.mPausingActivity;
+                if (r != null && r.state != ActivityState.PAUSED
+                        && r.state != ActivityState.STOPPED
+                        && r.state != ActivityState.STOPPING) {
+                    if (DEBUG_STATES) {
+                        Slog.d(TAG, "allPausedActivitiesComplete: r=" + r + " state=" + r.state);
+                        pausing = false;
+                    } else {
+                        return false;
+                    }
                 }
             }
         }
         return pausing;
     }
 
+    void pauseChildStacks(ActivityRecord parent, boolean userLeaving, boolean uiSleeping) {
+		// TODO: Put all stacks in supervisor and iterate through them instead.
+        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
+            ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
+            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = stacks.get(stackNdx);
+                if (stack.mResumedActivity != null &&
+                        stack.mActivityContainer.mParentActivity == parent) {
+                    stack.startPausingLocked(userLeaving, uiSleeping);
+                }
+            }
+        }
+    }
+
     void reportActivityVisibleLocked(ActivityRecord r) {
         for (int i = mWaitingActivityVisible.size()-1; i >= 0; i--) {
             WaitResult w = mWaitingActivityVisible.get(i);
@@ -525,8 +571,10 @@
             return r;
         }
 
-        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
-            final ActivityStack stack = mStacks.get(stackNdx);
+        // Return to the home stack.
+        final ArrayList<ActivityStack> stacks = mHomeStack.mStacks;
+        for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+            final ActivityStack stack = stacks.get(stackNdx);
             if (stack != focusedStack && isFrontStack(stack)) {
                 r = stack.topRunningActivityLocked(null);
                 if (r != null) {
@@ -542,15 +590,19 @@
         ActivityRecord r = null;
 
         // Gather all of the running tasks for each stack into runningTaskLists.
-        final int numStacks = mStacks.size();
-        ArrayList<RunningTaskInfo>[] runningTaskLists = new ArrayList[numStacks];
-        for (int stackNdx = numStacks - 1; stackNdx >= 0; --stackNdx) {
-            final ActivityStack stack = mStacks.get(stackNdx);
-            ArrayList<RunningTaskInfo> stackTaskList = new ArrayList<RunningTaskInfo>();
-            runningTaskLists[stackNdx] = stackTaskList;
-            final ActivityRecord ar = stack.getTasksLocked(receiver, pending, stackTaskList);
-            if (isFrontStack(stack)) {
-                r = ar;
+        ArrayList<ArrayList<RunningTaskInfo>> runningTaskLists =
+                new ArrayList<ArrayList<RunningTaskInfo>>();
+        final int numDisplays = mActivityDisplays.size();
+        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
+            ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
+            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = stacks.get(stackNdx);
+                ArrayList<RunningTaskInfo> stackTaskList = new ArrayList<RunningTaskInfo>();
+                runningTaskLists.add(stackTaskList);
+                final ActivityRecord ar = stack.getTasksLocked(receiver, pending, stackTaskList);
+                if (r == null && isFrontStack(stack)) {
+                    r = ar;
+                }
             }
         }
 
@@ -559,8 +611,9 @@
         while (maxNum > 0) {
             long mostRecentActiveTime = Long.MIN_VALUE;
             ArrayList<RunningTaskInfo> selectedStackList = null;
-            for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
-                ArrayList<RunningTaskInfo> stackTaskList = runningTaskLists[stackNdx];
+            final int numTaskLists = runningTaskLists.size();
+            for (int stackNdx = 0; stackNdx < numTaskLists; ++stackNdx) {
+                ArrayList<RunningTaskInfo> stackTaskList = runningTaskLists.get(stackNdx);
                 if (!stackTaskList.isEmpty()) {
                     final long lastActiveTime = stackTaskList.get(0).lastActiveTime;
                     if (lastActiveTime > mostRecentActiveTime) {
@@ -630,14 +683,14 @@
     void startHomeActivity(Intent intent, ActivityInfo aInfo) {
         moveHomeToTop();
         startActivityLocked(null, intent, null, aInfo, null, null, 0, 0, 0, null, 0,
-                null, false, null);
+                null, false, null, null);
     }
 
     final int startActivityMayWait(IApplicationThread caller, int callingUid,
             String callingPackage, Intent intent, String resolvedType, IBinder resultTo,
             String resultWho, int requestCode, int startFlags, String profileFile,
             ParcelFileDescriptor profileFd, WaitResult outResult, Configuration config,
-            Bundle options, int userId) {
+            Bundle options, int userId, IActivityContainer iContainer) {
         // Refuse possible leaked file descriptors
         if (intent != null && intent.hasFileDescriptors()) {
             throw new IllegalArgumentException("File descriptors passed in Intent");
@@ -651,6 +704,7 @@
         ActivityInfo aInfo = resolveActivity(intent, resolvedType, startFlags,
                 profileFile, profileFd, userId);
 
+        ActivityContainer container = (ActivityContainer)iContainer;
         synchronized (mService) {
             int callingPid;
             if (callingUid >= 0) {
@@ -662,7 +716,12 @@
                 callingPid = callingUid = -1;
             }
 
-            final ActivityStack stack = getFocusedStack();
+            final ActivityStack stack;
+            if (container == null || container.mStack.isOnHomeDisplay()) {
+                stack = getFocusedStack();
+            } else {
+                stack = container.mStack;
+            }
             stack.mConfigWillChange = config != null
                     && mService.mConfiguration.diff(config) != 0;
             if (DEBUG_CONFIGURATION) Slog.v(TAG,
@@ -738,9 +797,9 @@
                 }
             }
 
-            int res = startActivityLocked(caller, intent, resolvedType,
-                    aInfo, resultTo, resultWho, requestCode, callingPid, callingUid,
-                    callingPackage, startFlags, options, componentSpecified, null);
+            int res = startActivityLocked(caller, intent, resolvedType, aInfo, resultTo, resultWho,
+                    requestCode, callingPid, callingUid, callingPackage, startFlags, options,
+                    componentSpecified, null, container);
 
             if (stack.mConfigWillChange) {
                 // If the caller also wants to switch to a new configuration,
@@ -855,7 +914,7 @@
                     }
                     int res = startActivityLocked(caller, intent, resolvedTypes[i],
                             aInfo, resultTo, null, -1, callingPid, callingUid, callingPackage,
-                            0, theseOptions, componentSpecified, outActivity);
+                            0, theseOptions, componentSpecified, outActivity, null);
                     if (res < 0) {
                         return res;
                     }
@@ -1079,7 +1138,7 @@
             Intent intent, String resolvedType, ActivityInfo aInfo, IBinder resultTo,
             String resultWho, int requestCode,
             int callingPid, int callingUid, String callingPackage, int startFlags, Bundle options,
-            boolean componentSpecified, ActivityRecord[] outActivity) {
+            boolean componentSpecified, ActivityRecord[] outActivity, ActivityContainer container) {
         int err = ActivityManager.START_SUCCESS;
 
         ProcessRecord callerApp = null;
@@ -1099,7 +1158,11 @@
         if (err == ActivityManager.START_SUCCESS) {
             final int userId = aInfo != null ? UserHandle.getUserId(aInfo.applicationInfo.uid) : 0;
             Slog.i(TAG, "START u" + userId + " {" + intent.toShortString(true, true, true, false)
-                    + "} from pid " + (callerApp != null ? callerApp.pid : callingPid));
+                    + "} from pid " + (callerApp != null ? callerApp.pid : callingPid)
+                    + " on display " + (container == null ? (mFocusedStack == null ?
+                            Display.DEFAULT_DISPLAY : mFocusedStack.mDisplayId) :
+                            (container.mActivityDisplay == null ? Display.DEFAULT_DISPLAY :
+                                    container.mActivityDisplay.mDisplayId)));
         }
 
         ActivityRecord sourceRecord = null;
@@ -1227,8 +1290,8 @@
         }
 
         ActivityRecord r = new ActivityRecord(mService, callerApp, callingUid, callingPackage,
-                intent, resolvedType, aInfo, mService.mConfiguration,
-                resultRecord, resultWho, requestCode, componentSpecified, this);
+                intent, resolvedType, aInfo, mService.mConfiguration, resultRecord, resultWho,
+                requestCode, componentSpecified, this, container);
         if (outActivity != null) {
             outActivity[0] = r;
         }
@@ -1276,25 +1339,35 @@
         if (r.isApplicationActivity() || (task != null && task.isApplicationTask())) {
             if (task != null) {
                 final ActivityStack taskStack = task.stack;
-                if (mFocusedStack != taskStack) {
-                    if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG,
-                            "adjustStackFocus: Setting focused stack to r=" + r + " task=" + task);
-                    mFocusedStack = taskStack.isHomeStack() ? null : taskStack;
-                } else {
-                    if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG,
-                        "adjustStackFocus: Focused stack already=" + mFocusedStack);
+                if (taskStack.isOnHomeDisplay()) {
+                    if (mFocusedStack != taskStack) {
+                        if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG, "adjustStackFocus: Setting " +
+                                "focused stack to r=" + r + " task=" + task);
+                        mFocusedStack = taskStack;
+                    } else {
+                        if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG,
+                            "adjustStackFocus: Focused stack already=" + mFocusedStack);
+                    }
                 }
                 return taskStack;
             }
 
-            if (mFocusedStack != null) {
+            final ActivityContainer container = r.mInitialActivityContainer;
+            if (container != null) {
+                // The first time put it on the desired stack, after this put on task stack.
+                r.mInitialActivityContainer = null;
+                return container.mStack;
+            }
+
+            if (mFocusedStack != mHomeStack) {
                 if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG,
                         "adjustStackFocus: Have a focused stack=" + mFocusedStack);
                 return mFocusedStack;
             }
 
-            for (int stackNdx = mStacks.size() - 1; stackNdx > 0; --stackNdx) {
-                ActivityStack stack = mStacks.get(stackNdx);
+            final ArrayList<ActivityStack> homeDisplayStacks = mHomeStack.mStacks;
+            for (int stackNdx = homeDisplayStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = homeDisplayStacks.get(stackNdx);
                 if (!stack.isHomeStack()) {
                     if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG,
                             "adjustStackFocus: Setting focused stack=" + stack);
@@ -1303,9 +1376,8 @@
                 }
             }
 
-            // Time to create the first app stack for this user.
-            int stackId =
-                    mService.createStack(-1, HOME_STACK_ID, StackBox.TASK_STACK_GOES_OVER, 1.0f);
+            // Need to create an app stack for this user.
+            int stackId = createStackOnDisplay(getNextStackId(), Display.DEFAULT_DISPLAY);
             if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG, "adjustStackFocus: New stack r=" + r +
                     " stackId=" + stackId);
             mFocusedStack = getStack(stackId);
@@ -1315,30 +1387,17 @@
     }
 
     void setFocusedStack(ActivityRecord r) {
-        if (r == null) {
-            return;
-        }
-        if (!r.isApplicationActivity() || (r.task != null && !r.task.isApplicationTask())) {
-            if (mStackState != STACK_STATE_HOME_IN_FRONT) {
-                if (DEBUG_STACK || DEBUG_FOCUS) Slog.d(TAG, "setFocusedStack: mStackState old=" +
-                        stackStateToString(mStackState) + " new=" +
-                        stackStateToString(STACK_STATE_HOME_TO_FRONT) +
-                        " Callers=" + Debug.getCallers(3));
-                mStackState = STACK_STATE_HOME_TO_FRONT;
+        if (r != null) {
+            final TaskRecord task = r.task;
+            boolean isHomeActivity = !r.isApplicationActivity();
+            if (!isHomeActivity && task != null) {
+                isHomeActivity = !task.isApplicationTask();
             }
-        } else {
-            if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG,
-                    "setFocusedStack: Setting focused stack to r=" + r + " task=" + r.task +
-                    " Callers=" + Debug.getCallers(3));
-            final ActivityStack taskStack = r.task.stack;
-            mFocusedStack = taskStack.isHomeStack() ? null : taskStack;
-            if (mStackState != STACK_STATE_HOME_IN_BACK) {
-                if (DEBUG_STACK) Slog.d(TAG, "setFocusedStack: mStackState old=" +
-                        stackStateToString(mStackState) + " new=" +
-                        stackStateToString(STACK_STATE_HOME_TO_BACK) +
-                        " Callers=" + Debug.getCallers(3));
-                mStackState = STACK_STATE_HOME_TO_BACK;
+            if (!isHomeActivity && task != null) {
+                final ActivityRecord parent = task.stack.mActivityContainer.mParentActivity;
+                isHomeActivity = parent != null && parent.isHomeActivity();
             }
+            moveHomeStack(isHomeActivity);
         }
     }
 
@@ -1465,7 +1524,7 @@
                     targetStack.mLastPausedActivity = null;
                     if (DEBUG_TASKS) Slog.d(TAG, "Bring to front target: " + targetStack
                             + " from " + intentActivity);
-                    moveHomeStack(targetStack.isHomeStack());
+                    targetStack.moveToFront();
                     if (intentActivity.task.intent == null) {
                         // This task was started because of movement of
                         // the activity based on affinity...  now that we
@@ -1515,9 +1574,6 @@
                         } else {
                             ActivityOptions.abort(options);
                         }
-                        if (r.task == null)  Slog.v(TAG,
-                                "startActivityUncheckedLocked: task left null",
-                                new RuntimeException("here").fillInStackTrace());
                         return ActivityManager.START_RETURN_INTENT_TO_CALLER;
                     }
                     if ((launchFlags &
@@ -1610,9 +1666,6 @@
                         } else {
                             ActivityOptions.abort(options);
                         }
-                        if (r.task == null)  Slog.v(TAG,
-                            "startActivityUncheckedLocked: task left null",
-                            new RuntimeException("here").fillInStackTrace());
                         return ActivityManager.START_TASK_TO_FRONT;
                     }
                 }
@@ -1650,15 +1703,9 @@
                                 // We don't need to start a new activity, and
                                 // the client said not to do anything if that
                                 // is the case, so this is it!
-                                if (r.task == null)  Slog.v(TAG,
-                                    "startActivityUncheckedLocked: task left null",
-                                    new RuntimeException("here").fillInStackTrace());
                                 return ActivityManager.START_RETURN_INTENT_TO_CALLER;
                             }
                             top.deliverNewIntentLocked(callingUid, r.intent);
-                            if (r.task == null)  Slog.v(TAG,
-                                "startActivityUncheckedLocked: task left null",
-                                new RuntimeException("here").fillInStackTrace());
                             return ActivityManager.START_DELIVERED_TO_TOP;
                         }
                     }
@@ -1671,9 +1718,6 @@
                         r.requestCode, Activity.RESULT_CANCELED, null);
             }
             ActivityOptions.abort(options);
-            if (r.task == null)  Slog.v(TAG,
-                "startActivityUncheckedLocked: task left null",
-                new RuntimeException("here").fillInStackTrace());
             return ActivityManager.START_CLASS_NOT_FOUND;
         }
 
@@ -1684,7 +1728,7 @@
         if (r.resultTo == null && !addingToTask
                 && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
             targetStack = adjustStackFocus(r);
-            moveHomeStack(targetStack.isHomeStack());
+            targetStack.moveToFront();
             if (reuseTask == null) {
                 r.setTask(targetStack.createTaskRecord(getNextTaskId(),
                         newTaskInfo != null ? newTaskInfo : r.info,
@@ -1702,13 +1746,13 @@
                         == (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_TASK_ON_HOME)) {
                     // Caller wants to appear on home activity, so before starting
                     // their own activity we will bring home to the front.
-                    r.task.mOnTopOfHome = true;
+                    r.task.mOnTopOfHome = r.task.stack.isOnHomeDisplay();
                 }
             }
         } else if (sourceRecord != null) {
             TaskRecord sourceTask = sourceRecord.task;
             targetStack = sourceTask.stack;
-            moveHomeStack(targetStack.isHomeStack());
+            targetStack.moveToFront();
             mWindowManager.moveTaskToTop(sourceTask.taskId);
             if (!addingToTask &&
                     (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
@@ -1727,9 +1771,6 @@
                         targetStack.resumeTopActivityLocked(null);
                     }
                     ActivityOptions.abort(options);
-                    if (r.task == null)  Slog.w(TAG,
-                        "startActivityUncheckedLocked: task left null",
-                        new RuntimeException("here").fillInStackTrace());
                     return ActivityManager.START_DELIVERED_TO_TOP;
                 }
             } else if (!addingToTask &&
@@ -1763,7 +1804,7 @@
             // of a new task...  just put it in the top task, though these days
             // this case should never happen.
             targetStack = adjustStackFocus(r);
-            moveHomeStack(targetStack.isHomeStack());
+            targetStack.moveToFront();
             ActivityRecord prev = targetStack.topActivity();
             r.setTask(prev != null ? prev.task
                     : targetStack.createTaskRecord(getNextTaskId(), r.info, intent, true),
@@ -1956,17 +1997,21 @@
 
     boolean handleAppDiedLocked(ProcessRecord app) {
         boolean hasVisibleActivities = false;
-        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
-            hasVisibleActivities |= mStacks.get(stackNdx).handleAppDiedLocked(app);
+        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
+            final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
+            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+                hasVisibleActivities |= stacks.get(stackNdx).handleAppDiedLocked(app);
+            }
         }
         return hasVisibleActivities;
     }
 
     void closeSystemDialogsLocked() {
-        final int numStacks = mStacks.size();
-        for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
-            final ActivityStack stack = mStacks.get(stackNdx);
-            stack.closeSystemDialogsLocked();
+        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
+            final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
+            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+                stacks.get(stackNdx).closeSystemDialogsLocked();
+            }
         }
     }
 
@@ -1979,11 +2024,14 @@
      */
     boolean forceStopPackageLocked(String name, boolean doit, boolean evenPersistent, int userId) {
         boolean didSomething = false;
-        final int numStacks = mStacks.size();
-        for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
-            final ActivityStack stack = mStacks.get(stackNdx);
-            if (stack.forceStopPackageLocked(name, doit, evenPersistent, userId)) {
-                didSomething = true;
+        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
+            final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
+            final int numStacks = stacks.size();
+            for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
+                final ActivityStack stack = stacks.get(stackNdx);
+                if (stack.forceStopPackageLocked(name, doit, evenPersistent, userId)) {
+                    didSomething = true;
+                }
             }
         }
         return didSomething;
@@ -1998,15 +2046,18 @@
         // we don't blow away the previous app if this activity is being
         // hosted by the process that is actually still the foreground.
         ProcessRecord fgApp = null;
-        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
-            final ActivityStack stack = mStacks.get(stackNdx);
-            if (isFrontStack(stack)) {
-                if (stack.mResumedActivity != null) {
-                    fgApp = stack.mResumedActivity.app;
-                } else if (stack.mPausingActivity != null) {
-                    fgApp = stack.mPausingActivity.app;
+        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
+            final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
+            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = stacks.get(stackNdx);
+                if (isFrontStack(stack)) {
+                    if (stack.mResumedActivity != null) {
+                        fgApp = stack.mResumedActivity.app;
+                    } else if (stack.mPausingActivity != null) {
+                        fgApp = stack.mPausingActivity.app;
+                    }
+                    break;
                 }
-                break;
             }
         }
 
@@ -2029,13 +2080,20 @@
         if (targetStack == null) {
             targetStack = getFocusedStack();
         }
+        // Do targetStack first.
         boolean result = false;
-        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
-            final ActivityStack stack = mStacks.get(stackNdx);
-            if (isFrontStack(stack)) {
+        if (isFrontStack(targetStack)) {
+            result = targetStack.resumeTopActivityLocked(target, targetOptions);
+        }
+        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
+            final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
+            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = stacks.get(stackNdx);
                 if (stack == targetStack) {
-                    result = stack.resumeTopActivityLocked(target, targetOptions);
-                } else {
+                    // Already started above.
+                    continue;
+                }
+                if (isFrontStack(stack)) {
                     stack.resumeTopActivityLocked(null);
                 }
             }
@@ -2044,38 +2102,105 @@
     }
 
     void finishTopRunningActivityLocked(ProcessRecord app) {
-        final int numStacks = mStacks.size();
-        for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
-            final ActivityStack stack = mStacks.get(stackNdx);
-            stack.finishTopRunningActivityLocked(app);
+        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
+            final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
+            final int numStacks = stacks.size();
+            for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
+                final ActivityStack stack = stacks.get(stackNdx);
+                stack.finishTopRunningActivityLocked(app);
+            }
         }
     }
 
     void findTaskToMoveToFrontLocked(int taskId, int flags, Bundle options) {
-        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
-            if (mStacks.get(stackNdx).findTaskToMoveToFrontLocked(taskId, flags, options)) {
-                if (DEBUG_STACK) Slog.d(TAG, "findTaskToMoveToFront: moved to front of stack=" +
-                        mStacks.get(stackNdx));
-                return;
+        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
+            final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
+            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+                if (stacks.get(stackNdx).findTaskToMoveToFrontLocked(taskId, flags, options)) {
+                    if (DEBUG_STACK) Slog.d(TAG, "findTaskToMoveToFront: moved to front of stack="
+                            + stacks.get(stackNdx));
+                    return;
+                }
             }
         }
     }
 
     ActivityStack getStack(int stackId) {
-        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
-            final ActivityStack stack = mStacks.get(stackNdx);
-            if (stack.getStackId() == stackId) {
-                return stack;
-            }
+        ActivityContainer activityContainer = mActivityContainers.get(stackId);
+        if (activityContainer != null) {
+            return activityContainer.mStack;
         }
         return null;
     }
 
     ArrayList<ActivityStack> getStacks() {
-        return new ArrayList<ActivityStack>(mStacks);
+        ArrayList<ActivityStack> allStacks = new ArrayList<ActivityStack>();
+        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
+            allStacks.addAll(mActivityDisplays.valueAt(displayNdx).mStacks);
+        }
+        return allStacks;
     }
 
-    int createStack() {
+    IBinder getHomeActivityToken() {
+        final ArrayList<TaskRecord> tasks = mHomeStack.getAllTasks();
+        for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
+            final TaskRecord task = tasks.get(taskNdx);
+            if (task.isHomeTask()) {
+                final ArrayList<ActivityRecord> activities = task.mActivities;
+                for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
+                    final ActivityRecord r = activities.get(activityNdx);
+                    if (r.isHomeActivity()) {
+                        return r.appToken;
+                    }
+                }
+            }
+        }
+        return null;
+    }
+
+    ActivityContainer createActivityContainer(ActivityRecord parentActivity,
+            IActivityContainerCallback callback) {
+        ActivityContainer activityContainer = new VirtualActivityContainer(parentActivity, callback);
+        mActivityContainers.put(activityContainer.mStackId, activityContainer);
+        parentActivity.mChildContainers.add(activityContainer);
+        return activityContainer;
+    }
+
+    void removeChildActivityContainers(ActivityRecord parentActivity) {
+        final ArrayList<ActivityContainer> childStacks = parentActivity.mChildContainers;
+        for (int containerNdx = childStacks.size() - 1; containerNdx >= 0; --containerNdx) {
+            ActivityContainer container = childStacks.remove(containerNdx);
+            container.release();
+        }
+    }
+
+    void deleteActivityContainer(IActivityContainer container) {
+        ActivityContainer activityContainer = (ActivityContainer)container;
+        if (activityContainer != null) {
+            activityContainer.mStack.finishAllActivitiesLocked();
+            final ActivityRecord parent = activityContainer.mParentActivity;
+            if (parent != null) {
+                parent.mChildContainers.remove(activityContainer);
+            }
+            final int stackId = activityContainer.mStackId;
+            mActivityContainers.remove(stackId);
+            mWindowManager.removeStack(stackId);
+        }
+    }
+
+    private int createStackOnDisplay(int stackId, int displayId) {
+        ActivityDisplay activityDisplay = mActivityDisplays.get(displayId);
+        if (activityDisplay == null) {
+            return -1;
+        }
+
+        ActivityContainer activityContainer = new ActivityContainer(stackId);
+        mActivityContainers.put(stackId, activityContainer);
+        activityContainer.attachToDisplayLocked(activityDisplay);
+        return stackId;
+    }
+
+    int getNextStackId() {
         while (true) {
             if (++mLastStackId <= HOME_STACK_ID) {
                 mLastStackId = HOME_STACK_ID + 1;
@@ -2084,7 +2209,6 @@
                 break;
             }
         }
-        mStacks.add(new ActivityStack(mService, mContext, mLooper, mLastStackId));
         return mLastStackId;
     }
 
@@ -2098,7 +2222,7 @@
             Slog.w(TAG, "moveTaskToStack: no stack for id=" + stackId);
             return;
         }
-        removeTask(task);
+        task.stack.removeTask(task);
         stack.addTask(task, toTop);
         mWindowManager.addTask(taskId, stackId, toTop);
         resumeTopActivitiesLocked();
@@ -2106,15 +2230,18 @@
 
     ActivityRecord findTaskLocked(ActivityRecord r) {
         if (DEBUG_TASKS) Slog.d(TAG, "Looking for task of " + r);
-        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
-            final ActivityStack stack = mStacks.get(stackNdx);
-            if (!r.isApplicationActivity() && !stack.isHomeStack()) {
-                if (DEBUG_TASKS) Slog.d(TAG, "Skipping stack: " + stack);
-                continue;
-            }
-            final ActivityRecord ar = stack.findTaskLocked(r);
-            if (ar != null) {
-                return ar;
+        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
+            final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
+            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = stacks.get(stackNdx);
+                if (!r.isApplicationActivity() && !stack.isHomeStack()) {
+                    if (DEBUG_TASKS) Slog.d(TAG, "Skipping stack: " + stack);
+                    continue;
+                }
+                final ActivityRecord ar = stack.findTaskLocked(r);
+                if (ar != null) {
+                    return ar;
+                }
             }
         }
         if (DEBUG_TASKS) Slog.d(TAG, "No task found");
@@ -2122,10 +2249,13 @@
     }
 
     ActivityRecord findActivityLocked(Intent intent, ActivityInfo info) {
-        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
-            final ActivityRecord ar = mStacks.get(stackNdx).findActivityLocked(intent, info);
-            if (ar != null) {
-                return ar;
+        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
+            final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
+            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityRecord ar = stacks.get(stackNdx).findActivityLocked(intent, info);
+                if (ar != null) {
+                    return ar;
+                }
             }
         }
         return null;
@@ -2147,14 +2277,17 @@
     }
 
     boolean shutdownLocked(int timeout) {
-        boolean timedout = false;
         goingToSleepLocked();
 
+        boolean timedout = false;
         final long endTime = System.currentTimeMillis() + timeout;
         while (true) {
             boolean cantShutdown = false;
-            for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
-                cantShutdown |= mStacks.get(stackNdx).checkReadyForSleepLocked();
+            for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
+                final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
+                for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+                    cantShutdown |= stacks.get(stackNdx).checkReadyForSleepLocked();
+                }
             }
             if (cantShutdown) {
                 long timeRemaining = endTime - System.currentTimeMillis();
@@ -2185,11 +2318,14 @@
         if (mGoingToSleep.isHeld()) {
             mGoingToSleep.release();
         }
-        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
-            final ActivityStack stack = mStacks.get(stackNdx);
-            stack.awakeFromSleepingLocked();
-            if (isFrontStack(stack)) {
-                resumeTopActivitiesLocked();
+        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
+            final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
+            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = stacks.get(stackNdx);
+                stack.awakeFromSleepingLocked();
+                if (isFrontStack(stack)) {
+                    resumeTopActivitiesLocked();
+                }
             }
         }
         mGoingToSleepActivities.clear();
@@ -2208,8 +2344,11 @@
 
         if (!mSleepTimeout) {
             boolean dontSleep = false;
-            for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
-                dontSleep |= mStacks.get(stackNdx).checkReadyForSleepLocked();
+            for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
+                final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
+                for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+                    dontSleep |= stacks.get(stackNdx).checkReadyForSleepLocked();
+                }
             }
 
             if (mStoppingActivities.size() > 0) {
@@ -2232,8 +2371,11 @@
             }
         }
 
-        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
-            mStacks.get(stackNdx).goToSleep();
+        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
+            final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
+            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+                stacks.get(stackNdx).goToSleep();
+            }
         }
 
         removeSleepTimeouts();
@@ -2260,37 +2402,45 @@
     }
 
     void handleAppCrashLocked(ProcessRecord app) {
-        final int numStacks = mStacks.size();
-        for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
-            final ActivityStack stack = mStacks.get(stackNdx);
-            stack.handleAppCrashLocked(app);
+        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
+            final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
+            final int numStacks = stacks.size();
+            for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
+                final ActivityStack stack = stacks.get(stackNdx);
+                stack.handleAppCrashLocked(app);
+            }
         }
     }
 
     void ensureActivitiesVisibleLocked(ActivityRecord starting, int configChanges) {
         // First the front stacks. In case any are not fullscreen and are in front of home.
         boolean showHomeBehindStack = false;
-        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
-            final ActivityStack stack = mStacks.get(stackNdx);
-            if (isFrontStack(stack)) {
-                showHomeBehindStack =
-                        stack.ensureActivitiesVisibleLocked(starting, configChanges);
-            }
-        }
-        // Now do back stacks.
-        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
-            final ActivityStack stack = mStacks.get(stackNdx);
-            if (!isFrontStack(stack)) {
-                stack.ensureActivitiesVisibleLocked(starting, configChanges, showHomeBehindStack);
+        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
+            final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
+            final int topStackNdx = stacks.size() - 1;
+            for (int stackNdx = topStackNdx; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = stacks.get(stackNdx);
+                if (stackNdx == topStackNdx) {
+                    // Top stack.
+                    showHomeBehindStack =
+                            stack.ensureActivitiesVisibleLocked(starting, configChanges);
+                } else {
+                    // Back stack.
+                    stack.ensureActivitiesVisibleLocked(starting, configChanges,
+                            showHomeBehindStack);
+                }
             }
         }
     }
 
     void scheduleDestroyAllActivities(ProcessRecord app, String reason) {
-        final int numStacks = mStacks.size();
-        for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
-            final ActivityStack stack = mStacks.get(stackNdx);
-            stack.scheduleDestroyActivities(app, false, reason);
+        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
+            final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
+            final int numStacks = stacks.size();
+            for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
+                final ActivityStack stack = stacks.get(stackNdx);
+                stack.scheduleDestroyActivities(app, false, reason);
+            }
         }
     }
 
@@ -2300,8 +2450,13 @@
         mCurrentUser = userId;
 
         mStartingUsers.add(uss);
-        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
-            mStacks.get(stackNdx).switchUserLocked(userId);
+        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
+            final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
+            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = stacks.get(stackNdx);
+                stack.switchUserLocked(userId);
+                mWindowManager.moveTaskToTop(stack.topTask().taskId);
+            }
         }
 
         ActivityStack stack = getStack(restoreStackId);
@@ -2309,8 +2464,13 @@
             stack = mHomeStack;
         }
         final boolean homeInFront = stack.isHomeStack();
-        moveHomeStack(homeInFront);
-        mWindowManager.moveTaskToTop(stack.topTask().taskId);
+        if (stack.isOnHomeDisplay()) {
+            moveHomeStack(homeInFront);
+            mWindowManager.moveTaskToTop(stack.topTask().taskId);
+        } else {
+            // Stack was moved to another display while user was swapped out.
+            resumeHomeActivity(null);
+        }
         return homeInFront;
     }
 
@@ -2355,8 +2515,9 @@
     }
 
     void validateTopActivitiesLocked() {
-        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
-            final ActivityStack stack = mStacks.get(stackNdx);
+        // FIXME
+/*        for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+            final ActivityStack stack = stacks.get(stackNdx);
             final ActivityRecord r = stack.topRunningActivityLocked(null);
             final ActivityState state = r == null ? ActivityState.DESTROYED : r.state;
             if (isFrontStack(stack)) {
@@ -2386,26 +2547,18 @@
                 }
             }
         }
-    }
-
-    private static String stackStateToString(int stackState) {
-        switch (stackState) {
-            case STACK_STATE_HOME_IN_FRONT: return "STACK_STATE_HOME_IN_FRONT";
-            case STACK_STATE_HOME_TO_BACK: return "STACK_STATE_HOME_TO_BACK";
-            case STACK_STATE_HOME_IN_BACK: return "STACK_STATE_HOME_IN_BACK";
-            case STACK_STATE_HOME_TO_FRONT: return "STACK_STATE_HOME_TO_FRONT";
-            default: return "Unknown stackState=" + stackState;
-        }
+*/
     }
 
     public void dump(PrintWriter pw, String prefix) {
         pw.print(prefix); pw.print("mDismissKeyguardOnNextActivity=");
                 pw.println(mDismissKeyguardOnNextActivity);
         pw.print(prefix); pw.print("mFocusedStack=" + mFocusedStack);
-                pw.print(" mStackState="); pw.println(stackStateToString(mStackState));
+                pw.print(" mLastFocusedStack="); pw.println(mLastFocusedStack);
         pw.print(prefix); pw.println("mSleepTimeout=" + mSleepTimeout);
         pw.print(prefix); pw.println("mCurTaskId=" + mCurTaskId);
         pw.print(prefix); pw.println("mUserStackInFront=" + mUserStackInFront);
+        pw.print(prefix); pw.println("mActivityContainers=" + mActivityContainers);
     }
 
     ArrayList<ActivityRecord> getDumpActivitiesLocked(String name) {
@@ -2431,42 +2584,48 @@
             boolean dumpClient, String dumpPackage) {
         boolean printed = false;
         boolean needSep = false;
-        final int numStacks = mStacks.size();
-        for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
-            final ActivityStack stack = mStacks.get(stackNdx);
-            StringBuilder stackHeader = new StringBuilder(128);
-            stackHeader.append("  Stack #");
-            stackHeader.append(mStacks.indexOf(stack));
-            stackHeader.append(":");
-            printed |= stack.dumpActivitiesLocked(fd, pw, dumpAll, dumpClient, dumpPackage, needSep,
-                    stackHeader.toString());
-            printed |= dumpHistoryList(fd, pw, stack.mLRUActivities, "    ", "Run", false, !dumpAll,
-                    false, dumpPackage, true, "    Running activities (most recent first):", null);
+        for (int displayNdx = 0; displayNdx < mActivityDisplays.size(); ++displayNdx) {
+            ActivityDisplay activityDisplay = mActivityDisplays.valueAt(displayNdx);
+            pw.print("Display #"); pw.println(activityDisplay.mDisplayId);
+            ArrayList<ActivityStack> stacks = activityDisplay.mStacks;
+            final int numStacks = stacks.size();
+            for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
+                final ActivityStack stack = stacks.get(stackNdx);
+                StringBuilder stackHeader = new StringBuilder(128);
+                stackHeader.append("  Stack #");
+                stackHeader.append(stack.mStackId);
+                stackHeader.append(":");
+                printed |= stack.dumpActivitiesLocked(fd, pw, dumpAll, dumpClient, dumpPackage,
+                        needSep, stackHeader.toString());
+                printed |= dumpHistoryList(fd, pw, stack.mLRUActivities, "    ", "Run", false,
+                        !dumpAll, false, dumpPackage, true,
+                        "    Running activities (most recent first):", null);
 
-            needSep = printed;
-            boolean pr = printThisActivity(pw, stack.mPausingActivity, dumpPackage, needSep,
-                    "    mPausingActivity: ");
-            if (pr) {
-                printed = true;
-                needSep = false;
-            }
-            pr = printThisActivity(pw, stack.mResumedActivity, dumpPackage, needSep,
-                    "    mResumedActivity: ");
-            if (pr) {
-                printed = true;
-                needSep = false;
-            }
-            if (dumpAll) {
-                pr = printThisActivity(pw, stack.mLastPausedActivity, dumpPackage, needSep,
-                        "    mLastPausedActivity: ");
+                needSep = printed;
+                boolean pr = printThisActivity(pw, stack.mPausingActivity, dumpPackage, needSep,
+                        "    mPausingActivity: ");
                 if (pr) {
                     printed = true;
-                    needSep = true;
+                    needSep = false;
                 }
-                printed |= printThisActivity(pw, stack.mLastNoHistoryActivity, dumpPackage,
-                        needSep, "    mLastNoHistoryActivity: ");
+                pr = printThisActivity(pw, stack.mResumedActivity, dumpPackage, needSep,
+                        "    mResumedActivity: ");
+                if (pr) {
+                    printed = true;
+                    needSep = false;
+                }
+                if (dumpAll) {
+                    pr = printThisActivity(pw, stack.mLastPausedActivity, dumpPackage, needSep,
+                            "    mLastPausedActivity: ");
+                    if (pr) {
+                        printed = true;
+                        needSep = true;
+                    }
+                    printed |= printThisActivity(pw, stack.mLastNoHistoryActivity, dumpPackage,
+                            needSep, "    mLastNoHistoryActivity: ");
+                }
+                needSep = printed;
             }
-            needSep = printed;
         }
 
         printed |= dumpHistoryList(fd, pw, mFinishingActivities, "  ", "Fin", false, !dumpAll,
@@ -2583,7 +2742,9 @@
     }
 
     final void scheduleResumeTopActivities() {
-        mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG);
+        if (!mHandler.hasMessages(RESUME_TOP_ACTIVITY_MSG)) {
+            mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG);
+        }
     }
 
     void removeSleepTimeouts() {
@@ -2596,6 +2757,101 @@
         mHandler.sendEmptyMessageDelayed(SLEEP_TIMEOUT_MSG, SLEEP_TIMEOUT);
     }
 
+    @Override
+    public void onDisplayAdded(int displayId) {
+        mHandler.sendMessage(mHandler.obtainMessage(HANDLE_DISPLAY_ADDED, displayId, 0));
+    }
+
+    @Override
+    public void onDisplayRemoved(int displayId) {
+        mHandler.sendMessage(mHandler.obtainMessage(HANDLE_DISPLAY_REMOVED, displayId, 0));
+    }
+
+    @Override
+    public void onDisplayChanged(int displayId) {
+        mHandler.sendMessage(mHandler.obtainMessage(HANDLE_DISPLAY_CHANGED, displayId, 0));
+    }
+
+    public void handleDisplayAddedLocked(int displayId) {
+        boolean newDisplay;
+        synchronized (mService) {
+            newDisplay = mActivityDisplays.get(displayId) == null;
+            if (newDisplay) {
+                ActivityDisplay activityDisplay = new ActivityDisplay(displayId);
+                mActivityDisplays.put(displayId, activityDisplay);
+            }
+        }
+        if (newDisplay) {
+            mWindowManager.onDisplayAdded(displayId);
+        }
+    }
+
+    public void handleDisplayRemovedLocked(int displayId) {
+        synchronized (mService) {
+            ActivityDisplay activityDisplay = mActivityDisplays.get(displayId);
+            if (activityDisplay != null) {
+                ArrayList<ActivityStack> stacks = activityDisplay.mStacks;
+                for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+                    stacks.get(stackNdx).mActivityContainer.detachLocked();
+                }
+                mActivityDisplays.remove(displayId);
+            }
+        }
+        mWindowManager.onDisplayRemoved(displayId);
+    }
+
+    public void handleDisplayChangedLocked(int displayId) {
+        synchronized (mService) {
+            ActivityDisplay activityDisplay = mActivityDisplays.get(displayId);
+            if (activityDisplay != null) {
+                // TODO: Update the bounds.
+            }
+        }
+        mWindowManager.onDisplayChanged(displayId);
+    }
+
+    StackInfo getStackInfo(ActivityStack stack) {
+        StackInfo info = new StackInfo();
+        mWindowManager.getStackBounds(stack.mStackId, info.bounds);
+        info.displayId = Display.DEFAULT_DISPLAY;
+        info.stackId = stack.mStackId;
+
+        ArrayList<TaskRecord> tasks = stack.getAllTasks();
+        final int numTasks = tasks.size();
+        int[] taskIds = new int[numTasks];
+        String[] taskNames = new String[numTasks];
+        for (int i = 0; i < numTasks; ++i) {
+            final TaskRecord task = tasks.get(i);
+            taskIds[i] = task.taskId;
+            taskNames[i] = task.origActivity != null ? task.origActivity.flattenToString()
+                    : task.realActivity != null ? task.realActivity.flattenToString()
+                    : task.getTopActivity() != null ? task.getTopActivity().packageName
+                    : "unknown";
+        }
+        info.taskIds = taskIds;
+        info.taskNames = taskNames;
+        return info;
+    }
+
+    StackInfo getStackInfoLocked(int stackId) {
+        ActivityStack stack = getStack(stackId);
+        if (stack != null) {
+            return getStackInfo(stack);
+        }
+        return null;
+    }
+
+    ArrayList<StackInfo> getAllStackInfosLocked() {
+        ArrayList<StackInfo> list = new ArrayList<StackInfo>();
+        for (int displayNdx = 0; displayNdx < mActivityDisplays.size(); ++displayNdx) {
+            ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
+            for (int ndx = stacks.size() - 1; ndx >= 0; --ndx) {
+                list.add(getStackInfo(stacks.get(ndx)));
+            }
+        }
+        return list;
+    }
+
     private final class ActivityStackSupervisorHandler extends Handler {
 
         public ActivityStackSupervisorHandler(Looper looper) {
@@ -2659,7 +2915,393 @@
                         }
                     }
                 } break;
+                case HANDLE_DISPLAY_ADDED: {
+                    handleDisplayAddedLocked(msg.arg1);
+                } break;
+                case HANDLE_DISPLAY_CHANGED: {
+                    handleDisplayChangedLocked(msg.arg1);
+                } break;
+                case HANDLE_DISPLAY_REMOVED: {
+                    handleDisplayRemovedLocked(msg.arg1);
+                } break;
+                case CONTAINER_CALLBACK_VISIBILITY: {
+                    final ActivityContainer container = (ActivityContainer) msg.obj;
+                    try {
+                        // We only send this message if mCallback is non-null.
+                        container.mCallback.setVisible(container.asBinder(), msg.arg1 == 1);
+                    } catch (RemoteException e) {
+                    }
+                }
             }
         }
     }
+
+    class ActivityContainer extends android.app.IActivityContainer.Stub {
+        final static int FORCE_NEW_TASK_FLAGS = Intent.FLAG_ACTIVITY_NEW_TASK |
+                Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
+        final int mStackId;
+        IActivityContainerCallback mCallback = null;
+        final ActivityStack mStack;
+        ActivityRecord mParentActivity = null;
+        String mIdString;
+
+        boolean mVisible = true;
+
+        /** Display this ActivityStack is currently on. Null if not attached to a Display. */
+        ActivityDisplay mActivityDisplay;
+
+        final static int CONTAINER_STATE_HAS_SURFACE = 0;
+        final static int CONTAINER_STATE_NO_SURFACE = 1;
+        final static int CONTAINER_STATE_FINISHING = 2;
+        int mContainerState = CONTAINER_STATE_HAS_SURFACE;
+
+        ActivityContainer(int stackId) {
+            synchronized (mService) {
+                mStackId = stackId;
+                mStack = new ActivityStack(this);
+                mIdString = "ActivtyContainer{" + mStackId + "}";
+                if (DEBUG_STACK) Slog.d(TAG, "Creating " + this);
+            }
+        }
+
+        void attachToDisplayLocked(ActivityDisplay activityDisplay) {
+            if (DEBUG_STACK) Slog.d(TAG, "attachToDisplayLocked: " + this
+                    + " to display=" + activityDisplay);
+            mActivityDisplay = activityDisplay;
+            mStack.mDisplayId = activityDisplay.mDisplayId;
+            mStack.mStacks = activityDisplay.mStacks;
+
+            activityDisplay.attachActivities(mStack);
+            mWindowManager.attachStack(mStackId, activityDisplay.mDisplayId);
+        }
+
+        @Override
+        public void attachToDisplay(int displayId) {
+            synchronized (mService) {
+                ActivityDisplay activityDisplay = mActivityDisplays.get(displayId);
+                if (activityDisplay == null) {
+                    return;
+                }
+                attachToDisplayLocked(activityDisplay);
+            }
+        }
+
+        @Override
+        public int getDisplayId() {
+            if (mActivityDisplay != null) {
+                return mActivityDisplay.mDisplayId;
+            }
+            return -1;
+        }
+
+        @Override
+        public boolean injectEvent(InputEvent event) {
+            final long origId = Binder.clearCallingIdentity();
+            try {
+                if (mActivityDisplay != null) {
+                    return mInputManagerInternal.injectInputEvent(event,
+                            mActivityDisplay.mDisplayId,
+                            InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
+                }
+                return false;
+            } finally {
+                Binder.restoreCallingIdentity(origId);
+            }
+        }
+
+        @Override
+        public void release() {
+            mContainerState = CONTAINER_STATE_FINISHING;
+            mStack.finishAllActivitiesLocked();
+            detachLocked();
+            mWindowManager.removeStack(mStackId);
+        }
+
+        private void detachLocked() {
+            if (DEBUG_STACK) Slog.d(TAG, "detachLocked: " + this + " from display="
+                    + mActivityDisplay + " Callers=" + Debug.getCallers(2));
+            if (mActivityDisplay != null) {
+                mActivityDisplay.detachActivitiesLocked(mStack);
+                mActivityDisplay = null;
+                mStack.mDisplayId = -1;
+                mStack.mStacks = null;
+                mWindowManager.detachStack(mStackId);
+            }
+        }
+
+        @Override
+        public final int startActivity(Intent intent) {
+            mService.enforceNotIsolatedCaller("ActivityContainer.startActivity");
+            int userId = mService.handleIncomingUser(Binder.getCallingPid(),
+                    Binder.getCallingUid(), mCurrentUser, false, true, "ActivityContainer", null);
+            // TODO: Switch to user app stacks here.
+            intent.addFlags(FORCE_NEW_TASK_FLAGS);
+            String mimeType = intent.getType();
+            if (mimeType == null && intent.getData() != null
+                    && "content".equals(intent.getData().getScheme())) {
+                mimeType = mService.getProviderMimeType(intent.getData(), userId);
+            }
+            return startActivityMayWait(null, -1, null, intent, mimeType, null, null, 0, 0, null,
+                    null, null, null, null, userId, this);
+        }
+
+        @Override
+        public final int startActivityIntentSender(IIntentSender intentSender) {
+            mService.enforceNotIsolatedCaller("ActivityContainer.startActivityIntentSender");
+
+            if (!(intentSender instanceof PendingIntentRecord)) {
+                throw new IllegalArgumentException("Bad PendingIntent object");
+            }
+
+            return ((PendingIntentRecord)intentSender).sendInner(0, null, null, null, null, null,
+                    null, 0, FORCE_NEW_TASK_FLAGS, FORCE_NEW_TASK_FLAGS, null, this);
+        }
+
+        private void checkEmbeddedAllowedInner(Intent intent, String resolvedType) {
+            int userId = mService.handleIncomingUser(Binder.getCallingPid(),
+                    Binder.getCallingUid(), mCurrentUser, false, true, "ActivityContainer", null);
+            if (resolvedType == null) {
+                resolvedType = intent.getType();
+                if (resolvedType == null && intent.getData() != null
+                        && "content".equals(intent.getData().getScheme())) {
+                    resolvedType = mService.getProviderMimeType(intent.getData(), userId);
+                }
+            }
+            ActivityInfo aInfo = resolveActivity(intent, resolvedType, 0, null, null, userId);
+            if (aInfo != null && (aInfo.flags & ActivityInfo.FLAG_ALLOW_EMBEDDED) == 0) {
+                throw new SecurityException(
+                        "Attempt to embed activity that has not set allowEmbedded=\"true\"");
+            }
+        }
+
+        /** Throw a SecurityException if allowEmbedded is not true */
+        @Override
+        public final void checkEmbeddedAllowed(Intent intent) {
+            checkEmbeddedAllowedInner(intent, null);
+        }
+
+        /** Throw a SecurityException if allowEmbedded is not true */
+        @Override
+        public final void checkEmbeddedAllowedIntentSender(IIntentSender intentSender) {
+            if (!(intentSender instanceof PendingIntentRecord)) {
+                throw new IllegalArgumentException("Bad PendingIntent object");
+            }
+            PendingIntentRecord pendingIntent = (PendingIntentRecord) intentSender;
+            checkEmbeddedAllowedInner(pendingIntent.key.requestIntent,
+                    pendingIntent.key.requestResolvedType);
+        }
+
+        @Override
+        public IBinder asBinder() {
+            return this;
+        }
+
+        @Override
+        public void setSurface(Surface surface, int width, int height, int density) {
+            mService.enforceNotIsolatedCaller("ActivityContainer.attachToSurface");
+        }
+
+        ActivityStackSupervisor getOuter() {
+            return ActivityStackSupervisor.this;
+        }
+
+        boolean isAttached() {
+            return mActivityDisplay != null;
+        }
+
+        void getBounds(Point outBounds) {
+            if (mActivityDisplay != null) {
+                mActivityDisplay.getBounds(outBounds);
+            } else {
+                outBounds.set(0, 0);
+            }
+        }
+
+        // TODO: Make sure every change to ActivityRecord.visible results in a call to this.
+        void setVisible(boolean visible) {
+            if (mVisible != visible) {
+                mVisible = visible;
+                if (mCallback != null) {
+                    mHandler.obtainMessage(CONTAINER_CALLBACK_VISIBILITY, visible ? 1 : 0,
+                            0 /* unused */, this).sendToTarget();
+                }
+            }
+        }
+
+        void setDrawn() {
+        }
+
+        @Override
+        public String toString() {
+            return mIdString + (mActivityDisplay == null ? "N" : "A");
+        }
+    }
+
+    private class VirtualActivityContainer extends ActivityContainer {
+        Surface mSurface;
+        boolean mDrawn = false;
+
+        VirtualActivityContainer(ActivityRecord parent, IActivityContainerCallback callback) {
+            super(getNextStackId());
+            mParentActivity = parent;
+            mCallback = callback;
+            mContainerState = CONTAINER_STATE_NO_SURFACE;
+            mIdString = "VirtualActivtyContainer{" + mStackId + ", parent=" + mParentActivity + "}";
+        }
+
+        @Override
+        public void setSurface(Surface surface, int width, int height, int density) {
+            super.setSurface(surface, width, height, density);
+
+            synchronized (mService) {
+                final long origId = Binder.clearCallingIdentity();
+                try {
+                    setSurfaceLocked(surface, width, height, density);
+                } finally {
+                    Binder.restoreCallingIdentity(origId);
+                }
+            }
+        }
+
+        private void setSurfaceLocked(Surface surface, int width, int height, int density) {
+            if (mContainerState == CONTAINER_STATE_FINISHING) {
+                return;
+            }
+            VirtualActivityDisplay virtualActivityDisplay =
+                    (VirtualActivityDisplay) mActivityDisplay;
+            if (virtualActivityDisplay == null) {
+                virtualActivityDisplay =
+                        new VirtualActivityDisplay(width, height, density);
+                mActivityDisplay = virtualActivityDisplay;
+                mActivityDisplays.put(virtualActivityDisplay.mDisplayId, virtualActivityDisplay);
+                attachToDisplayLocked(virtualActivityDisplay);
+            }
+
+            if (mSurface != null) {
+                mSurface.release();
+            }
+
+            mSurface = surface;
+            if (surface != null) {
+                mStack.resumeTopActivityLocked(null);
+            } else {
+                mContainerState = CONTAINER_STATE_NO_SURFACE;
+                ((VirtualActivityDisplay) mActivityDisplay).setSurface(null);
+                if (mStack.mPausingActivity == null && mStack.mResumedActivity != null) {
+                    mStack.startPausingLocked(false, true);
+                }
+            }
+
+            setSurfaceIfReady();
+
+            if (DEBUG_STACK) Slog.d(TAG, "setSurface: " + this + " to display="
+                    + virtualActivityDisplay);
+        }
+
+        @Override
+        boolean isAttached() {
+            return mSurface != null && super.isAttached();
+        }
+
+        @Override
+        void setDrawn() {
+            synchronized (mService) {
+                mDrawn = true;
+                setSurfaceIfReady();
+            }
+        }
+
+        private void setSurfaceIfReady() {
+            if (DEBUG_STACK) Slog.v(TAG, "setSurfaceIfReady: mDrawn=" + mDrawn +
+                    " mContainerState=" + mContainerState + " mSurface=" + mSurface);
+            if (mDrawn && mSurface != null && mContainerState == CONTAINER_STATE_NO_SURFACE) {
+                ((VirtualActivityDisplay) mActivityDisplay).setSurface(mSurface);
+                mContainerState = CONTAINER_STATE_HAS_SURFACE;
+            }
+        }
+    }
+
+    /** Exactly one of these classes per Display in the system. Capable of holding zero or more
+     * attached {@link ActivityStack}s */
+    class ActivityDisplay {
+        /** Actual Display this object tracks. */
+        int mDisplayId;
+        Display mDisplay;
+        DisplayInfo mDisplayInfo = new DisplayInfo();
+
+        /** All of the stacks on this display. Order matters, topmost stack is in front of all other
+         * stacks, bottommost behind. Accessed directly by ActivityManager package classes */
+        final ArrayList<ActivityStack> mStacks = new ArrayList<ActivityStack>();
+
+        ActivityDisplay() {
+        }
+
+        ActivityDisplay(int displayId) {
+            init(mDisplayManager.getDisplay(displayId));
+        }
+
+        void init(Display display) {
+            mDisplay = display;
+            mDisplayId = display.getDisplayId();
+            mDisplay.getDisplayInfo(mDisplayInfo);
+        }
+
+        void attachActivities(ActivityStack stack) {
+            if (DEBUG_STACK) Slog.v(TAG, "attachActivities: attaching " + stack + " to displayId="
+                    + mDisplayId);
+            mStacks.add(stack);
+        }
+
+        void detachActivitiesLocked(ActivityStack stack) {
+            if (DEBUG_STACK) Slog.v(TAG, "detachActivitiesLocked: detaching " + stack
+                    + " from displayId=" + mDisplayId);
+            mStacks.remove(stack);
+        }
+
+        void getBounds(Point bounds) {
+            mDisplay.getDisplayInfo(mDisplayInfo);
+            bounds.x = mDisplayInfo.appWidth;
+            bounds.y = mDisplayInfo.appHeight;
+        }
+
+        @Override
+        public String toString() {
+            return "ActivityDisplay={" + mDisplayId + " numStacks=" + mStacks.size() + "}";
+        }
+    }
+
+    class VirtualActivityDisplay extends ActivityDisplay {
+        VirtualDisplay mVirtualDisplay;
+
+        VirtualActivityDisplay(int width, int height, int density) {
+            DisplayManagerGlobal dm = DisplayManagerGlobal.getInstance();
+            mVirtualDisplay = dm.createVirtualDisplay(mService.mContext, VIRTUAL_DISPLAY_BASE_NAME,
+                    width, height, density, null, DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC |
+                    DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY);
+
+            init(mVirtualDisplay.getDisplay());
+
+            mWindowManager.handleDisplayAdded(mDisplayId);
+        }
+
+        void setSurface(Surface surface) {
+            if (mVirtualDisplay != null) {
+                mVirtualDisplay.setSurface(surface);
+            }
+        }
+
+        @Override
+        void detachActivitiesLocked(ActivityStack stack) {
+            super.detachActivitiesLocked(stack);
+            if (mVirtualDisplay != null) {
+                mVirtualDisplay.release();
+                mVirtualDisplay = null;
+            }
+        }
+
+        @Override
+        public String toString() {
+            return "VirtualActivityDisplay={" + mDisplayId + "}";
+        }
+    }
 }
diff --git a/services/java/com/android/server/am/AppBindRecord.java b/services/core/java/com/android/server/am/AppBindRecord.java
similarity index 100%
rename from services/java/com/android/server/am/AppBindRecord.java
rename to services/core/java/com/android/server/am/AppBindRecord.java
diff --git a/services/java/com/android/server/am/AppErrorDialog.java b/services/core/java/com/android/server/am/AppErrorDialog.java
similarity index 100%
rename from services/java/com/android/server/am/AppErrorDialog.java
rename to services/core/java/com/android/server/am/AppErrorDialog.java
diff --git a/services/java/com/android/server/am/AppErrorResult.java b/services/core/java/com/android/server/am/AppErrorResult.java
similarity index 100%
rename from services/java/com/android/server/am/AppErrorResult.java
rename to services/core/java/com/android/server/am/AppErrorResult.java
diff --git a/services/java/com/android/server/am/AppNotRespondingDialog.java b/services/core/java/com/android/server/am/AppNotRespondingDialog.java
similarity index 100%
rename from services/java/com/android/server/am/AppNotRespondingDialog.java
rename to services/core/java/com/android/server/am/AppNotRespondingDialog.java
diff --git a/services/java/com/android/server/am/AppWaitingForDebuggerDialog.java b/services/core/java/com/android/server/am/AppWaitingForDebuggerDialog.java
similarity index 100%
rename from services/java/com/android/server/am/AppWaitingForDebuggerDialog.java
rename to services/core/java/com/android/server/am/AppWaitingForDebuggerDialog.java
diff --git a/services/java/com/android/server/am/BackupRecord.java b/services/core/java/com/android/server/am/BackupRecord.java
similarity index 100%
rename from services/java/com/android/server/am/BackupRecord.java
rename to services/core/java/com/android/server/am/BackupRecord.java
diff --git a/services/java/com/android/server/am/BaseErrorDialog.java b/services/core/java/com/android/server/am/BaseErrorDialog.java
similarity index 100%
rename from services/java/com/android/server/am/BaseErrorDialog.java
rename to services/core/java/com/android/server/am/BaseErrorDialog.java
diff --git a/services/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
similarity index 97%
rename from services/java/com/android/server/am/BatteryStatsService.java
rename to services/core/java/com/android/server/am/BatteryStatsService.java
index 2d59678..89e96fd 100644
--- a/services/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -24,6 +24,7 @@
 import android.content.pm.PackageManager;
 import android.os.BatteryStats;
 import android.os.Binder;
+import android.os.Handler;
 import android.os.IBinder;
 import android.os.Parcel;
 import android.os.Process;
@@ -54,8 +55,8 @@
     private boolean mBluetoothPendingStats;
     private BluetoothHeadset mBluetoothHeadset;
 
-    BatteryStatsService(String filename) {
-        mStats = new BatteryStatsImpl(filename);
+    BatteryStatsService(String filename, Handler handler) {
+        mStats = new BatteryStatsImpl(filename, handler);
     }
     
     public void publish(Context context) {
@@ -174,10 +175,10 @@
         }
     }
         
-    public void noteScreenOn() {
+    public void noteScreenState(int state) {
         enforceCallingPermission();
         synchronized (mStats) {
-            mStats.noteScreenOnLocked();
+            mStats.noteScreenStateLocked(state);
         }
     }
     
@@ -188,18 +189,6 @@
         }
     }
     
-    public void noteScreenOff() {
-        enforceCallingPermission();
-        synchronized (mStats) {
-            mStats.noteScreenOffLocked();
-        }
-    }
-
-    public void noteInputEvent() {
-        enforceCallingPermission();
-        mStats.noteInputEventAtomic();
-    }
-    
     public void noteUserActivity(int uid, int event) {
         enforceCallingPermission();
         synchronized (mStats) {
@@ -207,6 +196,13 @@
         }
     }
     
+    public void noteInteractive(boolean interactive) {
+        enforceCallingPermission();
+        synchronized (mStats) {
+            mStats.noteInteractiveLocked(interactive);
+        }
+    }
+    
     public void notePhoneOn() {
         enforceCallingPermission();
         synchronized (mStats) {
diff --git a/services/java/com/android/server/am/BroadcastFilter.java b/services/core/java/com/android/server/am/BroadcastFilter.java
similarity index 100%
rename from services/java/com/android/server/am/BroadcastFilter.java
rename to services/core/java/com/android/server/am/BroadcastFilter.java
diff --git a/services/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
similarity index 98%
rename from services/java/com/android/server/am/BroadcastQueue.java
rename to services/core/java/com/android/server/am/BroadcastQueue.java
index bfb667f..aef9e5c 100644
--- a/services/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -33,6 +33,7 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
+import android.os.Looper;
 import android.os.Message;
 import android.os.Process;
 import android.os.RemoteException;
@@ -132,7 +133,14 @@
     static final int BROADCAST_INTENT_MSG = ActivityManagerService.FIRST_BROADCAST_QUEUE_MSG;
     static final int BROADCAST_TIMEOUT_MSG = ActivityManagerService.FIRST_BROADCAST_QUEUE_MSG + 1;
 
-    final Handler mHandler = new Handler() {
+    final BroadcastHandler mHandler;
+
+    private final class BroadcastHandler extends Handler {
+        public BroadcastHandler(Looper looper) {
+            super(looper, null, true);
+        }
+
+        @Override
         public void handleMessage(Message msg) {
             switch (msg.what) {
                 case BROADCAST_INTENT_MSG: {
@@ -164,9 +172,10 @@
         }
     }
 
-    BroadcastQueue(ActivityManagerService service, String name, long timeoutPeriod,
-            boolean allowDelayBehindServices) {
+    BroadcastQueue(ActivityManagerService service, Handler handler,
+            String name, long timeoutPeriod, boolean allowDelayBehindServices) {
         mService = service;
+        mHandler = new BroadcastHandler(handler.getLooper());
         mQueueName = name;
         mTimeoutPeriod = timeoutPeriod;
         mDelayBehindServices = allowDelayBehindServices;
diff --git a/services/java/com/android/server/am/BroadcastRecord.java b/services/core/java/com/android/server/am/BroadcastRecord.java
similarity index 100%
rename from services/java/com/android/server/am/BroadcastRecord.java
rename to services/core/java/com/android/server/am/BroadcastRecord.java
diff --git a/services/java/com/android/server/am/CompatModeDialog.java b/services/core/java/com/android/server/am/CompatModeDialog.java
similarity index 100%
rename from services/java/com/android/server/am/CompatModeDialog.java
rename to services/core/java/com/android/server/am/CompatModeDialog.java
diff --git a/services/java/com/android/server/am/CompatModePackages.java b/services/core/java/com/android/server/am/CompatModePackages.java
similarity index 93%
rename from services/java/com/android/server/am/CompatModePackages.java
rename to services/core/java/com/android/server/am/CompatModePackages.java
index 4d5577b..ec500c2 100644
--- a/services/java/com/android/server/am/CompatModePackages.java
+++ b/services/core/java/com/android/server/am/CompatModePackages.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 package com.android.server.am;
 
 import java.io.File;
@@ -19,6 +35,7 @@
 import android.content.pm.IPackageManager;
 import android.content.res.CompatibilityInfo;
 import android.os.Handler;
+import android.os.Looper;
 import android.os.Message;
 import android.os.RemoteException;
 import android.util.AtomicFile;
@@ -41,22 +58,27 @@
 
     private static final int MSG_WRITE = ActivityManagerService.FIRST_COMPAT_MODE_MSG;
 
-    private final Handler mHandler = new Handler() {
-        @Override public void handleMessage(Message msg) {
+    private final CompatHandler mHandler;
+
+    private final class CompatHandler extends Handler {
+        public CompatHandler(Looper looper) {
+            super(looper, null, true);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
             switch (msg.what) {
                 case MSG_WRITE:
                     saveCompatModes();
                     break;
-                default:
-                    super.handleMessage(msg);
-                    break;
             }
         }
     };
 
-    public CompatModePackages(ActivityManagerService service, File systemDir) {
+    public CompatModePackages(ActivityManagerService service, File systemDir, Handler handler) {
         mService = service;
         mFile = new AtomicFile(new File(systemDir, "packages-compat.xml"));
+        mHandler = new CompatHandler(handler.getLooper());
 
         FileInputStream fis = null;
         try {
diff --git a/services/java/com/android/server/am/ConnectionRecord.java b/services/core/java/com/android/server/am/ConnectionRecord.java
similarity index 100%
rename from services/java/com/android/server/am/ConnectionRecord.java
rename to services/core/java/com/android/server/am/ConnectionRecord.java
diff --git a/services/java/com/android/server/am/ContentProviderConnection.java b/services/core/java/com/android/server/am/ContentProviderConnection.java
similarity index 100%
rename from services/java/com/android/server/am/ContentProviderConnection.java
rename to services/core/java/com/android/server/am/ContentProviderConnection.java
diff --git a/services/java/com/android/server/am/ContentProviderRecord.java b/services/core/java/com/android/server/am/ContentProviderRecord.java
similarity index 100%
rename from services/java/com/android/server/am/ContentProviderRecord.java
rename to services/core/java/com/android/server/am/ContentProviderRecord.java
diff --git a/services/java/com/android/server/am/CoreSettingsObserver.java b/services/core/java/com/android/server/am/CoreSettingsObserver.java
similarity index 100%
rename from services/java/com/android/server/am/CoreSettingsObserver.java
rename to services/core/java/com/android/server/am/CoreSettingsObserver.java
diff --git a/services/java/com/android/server/am/EventLogTags.logtags b/services/core/java/com/android/server/am/EventLogTags.logtags
similarity index 100%
rename from services/java/com/android/server/am/EventLogTags.logtags
rename to services/core/java/com/android/server/am/EventLogTags.logtags
diff --git a/services/java/com/android/server/am/FactoryErrorDialog.java b/services/core/java/com/android/server/am/FactoryErrorDialog.java
similarity index 100%
rename from services/java/com/android/server/am/FactoryErrorDialog.java
rename to services/core/java/com/android/server/am/FactoryErrorDialog.java
diff --git a/services/java/com/android/server/am/IntentBindRecord.java b/services/core/java/com/android/server/am/IntentBindRecord.java
similarity index 100%
rename from services/java/com/android/server/am/IntentBindRecord.java
rename to services/core/java/com/android/server/am/IntentBindRecord.java
diff --git a/services/java/com/android/server/am/LaunchWarningWindow.java b/services/core/java/com/android/server/am/LaunchWarningWindow.java
similarity index 100%
rename from services/java/com/android/server/am/LaunchWarningWindow.java
rename to services/core/java/com/android/server/am/LaunchWarningWindow.java
diff --git a/services/java/com/android/server/am/NativeCrashListener.java b/services/core/java/com/android/server/am/NativeCrashListener.java
similarity index 99%
rename from services/java/com/android/server/am/NativeCrashListener.java
rename to services/core/java/com/android/server/am/NativeCrashListener.java
index 493e1e4..d42d415 100644
--- a/services/java/com/android/server/am/NativeCrashListener.java
+++ b/services/core/java/com/android/server/am/NativeCrashListener.java
@@ -95,8 +95,8 @@
      * Daemon thread that accept()s incoming domain socket connections from debuggerd
      * and processes the crash dump that is passed through.
      */
-    NativeCrashListener() {
-        mAm = ActivityManagerService.self();
+    NativeCrashListener(ActivityManagerService am) {
+        mAm = am;
     }
 
     @Override
diff --git a/services/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java
similarity index 97%
rename from services/java/com/android/server/am/PendingIntentRecord.java
rename to services/core/java/com/android/server/am/PendingIntentRecord.java
index 17f24a9..00fa216 100644
--- a/services/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/core/java/com/android/server/am/PendingIntentRecord.java
@@ -17,6 +17,7 @@
 package com.android.server.am;
 
 import android.app.ActivityManager;
+import android.app.IActivityContainer;
 import android.content.IIntentSender;
 import android.content.IIntentReceiver;
 import android.app.PendingIntent;
@@ -190,13 +191,13 @@
     public int send(int code, Intent intent, String resolvedType,
             IIntentReceiver finishedReceiver, String requiredPermission) {
         return sendInner(code, intent, resolvedType, finishedReceiver,
-                requiredPermission, null, null, 0, 0, 0, null);
+                requiredPermission, null, null, 0, 0, 0, null, null);
     }
     
     int sendInner(int code, Intent intent, String resolvedType,
             IIntentReceiver finishedReceiver, String requiredPermission,
             IBinder resultTo, String resultWho, int requestCode,
-            int flagsMask, int flagsValues, Bundle options) {
+            int flagsMask, int flagsValues, Bundle options, IActivityContainer container) {
         synchronized(owner) {
             if (!canceled) {
                 sent = true;
@@ -251,7 +252,7 @@
                             } else {
                                 owner.startActivityInPackage(uid, key.packageName, finalIntent,
                                         resolvedType, resultTo, resultWho, requestCode, 0,
-                                        options, userId);
+                                        options, userId, container);
                             }
                         } catch (RuntimeException e) {
                             Slog.w(ActivityManagerService.TAG,
@@ -302,7 +303,8 @@
         }
         return ActivityManager.START_CANCELED;
     }
-    
+
+    @Override
     protected void finalize() throws Throwable {
         try {
             if (!canceled) {
diff --git a/services/java/com/android/server/am/PendingThumbnailsRecord.java b/services/core/java/com/android/server/am/PendingThumbnailsRecord.java
similarity index 100%
rename from services/java/com/android/server/am/PendingThumbnailsRecord.java
rename to services/core/java/com/android/server/am/PendingThumbnailsRecord.java
diff --git a/services/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
similarity index 86%
rename from services/java/com/android/server/am/ProcessList.java
rename to services/core/java/com/android/server/am/ProcessList.java
index d3777c7..f5920c8 100644
--- a/services/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -18,6 +18,8 @@
 
 import java.io.FileOutputStream;
 import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
 
 import android.app.ActivityManager;
 import com.android.internal.util.MemInfoReader;
@@ -26,6 +28,8 @@
 import android.content.res.Resources;
 import android.graphics.Point;
 import android.os.SystemProperties;
+import android.net.LocalSocketAddress;
+import android.net.LocalSocket;
 import android.util.Slog;
 import android.view.Display;
 
@@ -141,6 +145,16 @@
     // Threshold of number of cached+empty where we consider memory critical.
     static final int TRIM_LOW_THRESHOLD = 5;
 
+    // Low Memory Killer Daemon command codes.
+    // These must be kept in sync with the definitions in lmkd.c
+    //
+    // LMK_TARGET <minfree> <minkillprio> ... (up to 6 pairs)
+    // LMK_PROCPRIO <pid> <prio>
+    // LMK_PROCREMOVE <pid>
+    static final byte LMK_TARGET = 0;
+    static final byte LMK_PROCPRIO = 1;
+    static final byte LMK_PROCREMOVE = 2;
+
     // These are the various interesting memory levels that we will give to
     // the OOM killer.  Note that the OOM killer only supports 6 slots, so we
     // can't give it a different value for every possible kind of process.
@@ -150,18 +164,18 @@
     };
     // These are the low-end OOM level limits.  This is appropriate for an
     // HVGA or smaller phone with less than 512MB.  Values are in KB.
-    private final long[] mOomMinFreeLow = new long[] {
+    private final int[] mOomMinFreeLow = new int[] {
             8192, 12288, 16384,
             24576, 28672, 32768
     };
     // These are the high-end OOM level limits.  This is appropriate for a
     // 1280x800 or larger screen with around 1GB RAM.  Values are in KB.
-    private final long[] mOomMinFreeHigh = new long[] {
+    private final int[] mOomMinFreeHigh = new int[] {
             49152, 61440, 73728,
             86016, 98304, 122880
     };
     // The actual OOM killer memory levels we are using.
-    private final long[] mOomMinFree = new long[mOomAdj.length];
+    private final int[] mOomMinFree = new int[mOomAdj.length];
 
     private final long mTotalMemMb;
 
@@ -169,6 +183,9 @@
 
     private boolean mHaveDisplaySize;
 
+    private static LocalSocket sLmkdSocket;
+    private static OutputStream sLmkdOutputStream;
+
     ProcessList() {
         MemInfoReader minfo = new MemInfoReader();
         minfo.readMemInfo();
@@ -202,9 +219,6 @@
                     + " dh=" + displayHeight);
         }
 
-        StringBuilder adjString = new StringBuilder();
-        StringBuilder memString = new StringBuilder();
-
         float scale = scaleMem > scaleDisp ? scaleMem : scaleDisp;
         if (scale < 0) scale = 0;
         else if (scale > 1) scale = 1;
@@ -217,20 +231,20 @@
         }
 
         for (int i=0; i<mOomAdj.length; i++) {
-            long low = mOomMinFreeLow[i];
-            long high = mOomMinFreeHigh[i];
-            mOomMinFree[i] = (long)(low + ((high-low)*scale));
+            int low = mOomMinFreeLow[i];
+            int high = mOomMinFreeHigh[i];
+            mOomMinFree[i] = (int)(low + ((high-low)*scale));
         }
 
         if (minfree_abs >= 0) {
             for (int i=0; i<mOomAdj.length; i++) {
-                mOomMinFree[i] = (long)((float)minfree_abs * mOomMinFree[i] / mOomMinFree[mOomAdj.length - 1]);
+                mOomMinFree[i] = (int)((float)minfree_abs * mOomMinFree[i] / mOomMinFree[mOomAdj.length - 1]);
             }
         }
 
         if (minfree_adj != 0) {
             for (int i=0; i<mOomAdj.length; i++) {
-                mOomMinFree[i] += (long)((float)minfree_adj * mOomMinFree[i] / mOomMinFree[mOomAdj.length - 1]);
+                mOomMinFree[i] += (int)((float)minfree_adj * mOomMinFree[i] / mOomMinFree[mOomAdj.length - 1]);
                 if (mOomMinFree[i] < 0) {
                     mOomMinFree[i] = 0;
                 }
@@ -242,15 +256,6 @@
         // before killing background processes.
         mCachedRestoreLevel = (getMemLevel(ProcessList.CACHED_APP_MAX_ADJ)/1024) / 3;
 
-        for (int i=0; i<mOomAdj.length; i++) {
-            if (i > 0) {
-                adjString.append(',');
-                memString.append(',');
-            }
-            adjString.append(mOomAdj[i]);
-            memString.append((mOomMinFree[i]*1024)/PAGE_SIZE);
-        }
-
         // Ask the kernel to try to keep enough memory free to allocate 3 full
         // screen 32bpp buffers without entering direct reclaim.
         int reserve = displayWidth * displayHeight * 4 * 3 / 1024;
@@ -268,10 +273,15 @@
             }
         }
 
-        //Slog.i("XXXXXXX", "******************************* MINFREE: " + memString);
         if (write) {
-            writeFile("/sys/module/lowmemorykiller/parameters/adj", adjString.toString());
-            writeFile("/sys/module/lowmemorykiller/parameters/minfree", memString.toString());
+            ByteBuffer buf = ByteBuffer.allocate(4 * (2*mOomAdj.length + 1));
+            buf.putInt(LMK_TARGET);
+            for (int i=0; i<mOomAdj.length; i++) {
+                buf.putInt((mOomMinFree[i]*1024)/PAGE_SIZE);
+                buf.putInt(mOomAdj[i]);
+            }
+
+            writeLmkd(buf);
             SystemProperties.set("sys.sysctl.extra_free_kbytes", Integer.toString(reserve));
         }
         // GB: 2048,3072,4096,6144,7168,8192
@@ -506,19 +516,78 @@
         return mCachedRestoreLevel;
     }
 
-    private void writeFile(String path, String data) {
-        FileOutputStream fos = null;
+    /**
+     * Set the out-of-memory badness adjustment for a process.
+     *
+     * @param pid The process identifier to set.
+     * @param amt Adjustment value -- lmkd allows -16 to +15.
+     *
+     * {@hide}
+     */
+    public static final void setOomAdj(int pid, int amt) {
+        if (amt == UNKNOWN_ADJ)
+            return;
+
+        ByteBuffer buf = ByteBuffer.allocate(4 * 3);
+        buf.putInt(LMK_PROCPRIO);
+        buf.putInt(pid);
+        buf.putInt(amt);
+        writeLmkd(buf);
+    }
+
+    /*
+     * {@hide}
+     */
+    public static final void remove(int pid) {
+        ByteBuffer buf = ByteBuffer.allocate(4 * 2);
+        buf.putInt(LMK_PROCREMOVE);
+        buf.putInt(pid);
+        writeLmkd(buf);
+    }
+
+    private static boolean openLmkdSocket() {
         try {
-            fos = new FileOutputStream(path);
-            fos.write(data.getBytes());
-        } catch (IOException e) {
-            Slog.w(ActivityManagerService.TAG, "Unable to write " + path);
-        } finally {
-            if (fos != null) {
+            sLmkdSocket = new LocalSocket(LocalSocket.SOCKET_SEQPACKET);
+            sLmkdSocket.connect(
+                new LocalSocketAddress("lmkd",
+                        LocalSocketAddress.Namespace.RESERVED));
+            sLmkdOutputStream = sLmkdSocket.getOutputStream();
+        } catch (IOException ex) {
+            Slog.w(ActivityManagerService.TAG,
+                   "lowmemorykiller daemon socket open failed");
+            sLmkdSocket = null;
+            return false;
+        }
+
+        return true;
+    }
+
+    private static void writeLmkd(ByteBuffer buf) {
+
+        for (int i = 0; i < 3; i++) {
+            if (sLmkdSocket == null) {
+                    if (openLmkdSocket() == false) {
+                        try {
+                            Thread.sleep(1000);
+                        } catch (InterruptedException ie) {
+                        }
+                        continue;
+                    }
+            }
+
+            try {
+                sLmkdOutputStream.write(buf.array(), 0, buf.position());
+                return;
+            } catch (IOException ex) {
+                Slog.w(ActivityManagerService.TAG,
+                       "Error writing to lowmemorykiller socket");
+
                 try {
-                    fos.close();
-                } catch (IOException e) {
+                    sLmkdSocket.close();
+                } catch (IOException ex2) {
                 }
+
+                sLmkdSocket = null;
             }
         }
     }
diff --git a/services/java/com/android/server/am/ProcessMemInfo.java b/services/core/java/com/android/server/am/ProcessMemInfo.java
similarity index 100%
rename from services/java/com/android/server/am/ProcessMemInfo.java
rename to services/core/java/com/android/server/am/ProcessMemInfo.java
diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
similarity index 100%
rename from services/java/com/android/server/am/ProcessRecord.java
rename to services/core/java/com/android/server/am/ProcessRecord.java
diff --git a/services/java/com/android/server/am/ProcessStatsService.java b/services/core/java/com/android/server/am/ProcessStatsService.java
similarity index 100%
rename from services/java/com/android/server/am/ProcessStatsService.java
rename to services/core/java/com/android/server/am/ProcessStatsService.java
diff --git a/services/java/com/android/server/am/ProviderMap.java b/services/core/java/com/android/server/am/ProviderMap.java
similarity index 100%
rename from services/java/com/android/server/am/ProviderMap.java
rename to services/core/java/com/android/server/am/ProviderMap.java
diff --git a/services/java/com/android/server/am/ReceiverList.java b/services/core/java/com/android/server/am/ReceiverList.java
similarity index 100%
rename from services/java/com/android/server/am/ReceiverList.java
rename to services/core/java/com/android/server/am/ReceiverList.java
diff --git a/services/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
similarity index 98%
rename from services/java/com/android/server/am/ServiceRecord.java
rename to services/core/java/com/android/server/am/ServiceRecord.java
index 80e6e94..cb04835 100644
--- a/services/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -18,7 +18,8 @@
 
 import com.android.internal.app.ProcessStats;
 import com.android.internal.os.BatteryStatsImpl;
-import com.android.server.NotificationManagerService;
+import com.android.server.LocalServices;
+import com.android.server.notification.NotificationManagerInternal;
 
 import android.app.INotificationManager;
 import android.app.Notification;
@@ -427,8 +428,8 @@
             final Notification localForegroundNoti = foregroundNoti;
             ams.mHandler.post(new Runnable() {
                 public void run() {
-                    NotificationManagerService nm =
-                            (NotificationManagerService) NotificationManager.getService();
+                    NotificationManagerInternal nm = LocalServices.getService(
+                            NotificationManagerInternal.class);
                     if (nm == null) {
                         return;
                     }
@@ -479,7 +480,7 @@
                             throw new RuntimeException("icon must be non-zero");
                         }
                         int[] outId = new int[1];
-                        nm.enqueueNotificationInternal(localPackageName, localPackageName,
+                        nm.enqueueNotification(localPackageName, localPackageName,
                                 appUid, appPid, null, localForegroundId, localForegroundNoti,
                                 outId, userId);
                     } catch (RuntimeException e) {
diff --git a/services/java/com/android/server/am/StrictModeViolationDialog.java b/services/core/java/com/android/server/am/StrictModeViolationDialog.java
similarity index 100%
rename from services/java/com/android/server/am/StrictModeViolationDialog.java
rename to services/core/java/com/android/server/am/StrictModeViolationDialog.java
diff --git a/services/java/com/android/server/am/TaskAccessInfo.java b/services/core/java/com/android/server/am/TaskAccessInfo.java
similarity index 100%
rename from services/java/com/android/server/am/TaskAccessInfo.java
rename to services/core/java/com/android/server/am/TaskAccessInfo.java
diff --git a/services/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
similarity index 99%
rename from services/java/com/android/server/am/TaskRecord.java
rename to services/core/java/com/android/server/am/TaskRecord.java
index 9105103..9740812 100644
--- a/services/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -60,7 +60,8 @@
     /** Takes on same set of values as ActivityRecord.mActivityType */
     private int mTaskType;
 
-    /** Launch the home activity when leaving this task. */
+    /** Launch the home activity when leaving this task. Will be false for tasks that are not on
+     * Display.DEFAULT_DISPLAY. */
     boolean mOnTopOfHome = false;
 
     TaskRecord(int _taskId, ActivityInfo info, Intent _intent) {
diff --git a/services/java/com/android/server/am/ThumbnailHolder.java b/services/core/java/com/android/server/am/ThumbnailHolder.java
similarity index 100%
rename from services/java/com/android/server/am/ThumbnailHolder.java
rename to services/core/java/com/android/server/am/ThumbnailHolder.java
diff --git a/services/java/com/android/server/am/UriPermission.java b/services/core/java/com/android/server/am/UriPermission.java
similarity index 100%
rename from services/java/com/android/server/am/UriPermission.java
rename to services/core/java/com/android/server/am/UriPermission.java
diff --git a/services/java/com/android/server/am/UriPermissionOwner.java b/services/core/java/com/android/server/am/UriPermissionOwner.java
similarity index 100%
rename from services/java/com/android/server/am/UriPermissionOwner.java
rename to services/core/java/com/android/server/am/UriPermissionOwner.java
diff --git a/services/java/com/android/server/am/UsageStatsService.java b/services/core/java/com/android/server/am/UsageStatsService.java
similarity index 100%
rename from services/java/com/android/server/am/UsageStatsService.java
rename to services/core/java/com/android/server/am/UsageStatsService.java
diff --git a/services/java/com/android/server/am/UserStartedState.java b/services/core/java/com/android/server/am/UserStartedState.java
similarity index 100%
rename from services/java/com/android/server/am/UserStartedState.java
rename to services/core/java/com/android/server/am/UserStartedState.java
diff --git a/services/java/com/android/server/am/package.html b/services/core/java/com/android/server/am/package.html
similarity index 100%
rename from services/java/com/android/server/am/package.html
rename to services/core/java/com/android/server/am/package.html
diff --git a/services/java/com/android/server/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java
similarity index 99%
rename from services/java/com/android/server/ClipboardService.java
rename to services/core/java/com/android/server/clipboard/ClipboardService.java
index 069ae23..6aa596d 100644
--- a/services/java/com/android/server/ClipboardService.java
+++ b/services/core/java/com/android/server/clipboard/ClipboardService.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server;
+package com.android.server.clipboard;
 
 import android.app.ActivityManagerNative;
 import android.app.AppGlobals;
diff --git a/services/java/com/android/server/connectivity/DataConnectionStats.java b/services/core/java/com/android/server/connectivity/DataConnectionStats.java
similarity index 100%
rename from services/java/com/android/server/connectivity/DataConnectionStats.java
rename to services/core/java/com/android/server/connectivity/DataConnectionStats.java
diff --git a/services/java/com/android/server/connectivity/Nat464Xlat.java b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
similarity index 100%
rename from services/java/com/android/server/connectivity/Nat464Xlat.java
rename to services/core/java/com/android/server/connectivity/Nat464Xlat.java
diff --git a/services/java/com/android/server/connectivity/PacManager.java b/services/core/java/com/android/server/connectivity/PacManager.java
similarity index 100%
rename from services/java/com/android/server/connectivity/PacManager.java
rename to services/core/java/com/android/server/connectivity/PacManager.java
diff --git a/services/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
similarity index 100%
rename from services/java/com/android/server/connectivity/Tethering.java
rename to services/core/java/com/android/server/connectivity/Tethering.java
diff --git a/services/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
similarity index 100%
rename from services/java/com/android/server/connectivity/Vpn.java
rename to services/core/java/com/android/server/connectivity/Vpn.java
diff --git a/services/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
similarity index 100%
rename from services/java/com/android/server/content/ContentService.java
rename to services/core/java/com/android/server/content/ContentService.java
diff --git a/services/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
similarity index 100%
rename from services/java/com/android/server/content/SyncManager.java
rename to services/core/java/com/android/server/content/SyncManager.java
diff --git a/services/java/com/android/server/content/SyncOperation.java b/services/core/java/com/android/server/content/SyncOperation.java
similarity index 100%
rename from services/java/com/android/server/content/SyncOperation.java
rename to services/core/java/com/android/server/content/SyncOperation.java
diff --git a/services/java/com/android/server/content/SyncQueue.java b/services/core/java/com/android/server/content/SyncQueue.java
similarity index 100%
rename from services/java/com/android/server/content/SyncQueue.java
rename to services/core/java/com/android/server/content/SyncQueue.java
diff --git a/services/java/com/android/server/content/SyncStorageEngine.java b/services/core/java/com/android/server/content/SyncStorageEngine.java
similarity index 100%
rename from services/java/com/android/server/content/SyncStorageEngine.java
rename to services/core/java/com/android/server/content/SyncStorageEngine.java
diff --git a/services/java/com/android/server/display/DisplayAdapter.java b/services/core/java/com/android/server/display/DisplayAdapter.java
similarity index 100%
rename from services/java/com/android/server/display/DisplayAdapter.java
rename to services/core/java/com/android/server/display/DisplayAdapter.java
diff --git a/services/java/com/android/server/power/DisplayBlanker.java b/services/core/java/com/android/server/display/DisplayBlanker.java
similarity index 78%
rename from services/java/com/android/server/power/DisplayBlanker.java
rename to services/core/java/com/android/server/display/DisplayBlanker.java
index 6072053..eb0ae6a 100644
--- a/services/java/com/android/server/power/DisplayBlanker.java
+++ b/services/core/java/com/android/server/display/DisplayBlanker.java
@@ -14,12 +14,11 @@
  * limitations under the License.
  */
 
-package com.android.server.power;
+package com.android.server.display;
 
 /**
- * Blanks or unblanks all displays.
+ * Interface used to update the actual display state.
  */
-interface DisplayBlanker {
-    public void blankAllDisplays();
-    public void unblankAllDisplays();
+public interface DisplayBlanker {
+    void requestDisplayState(int state);
 }
diff --git a/services/java/com/android/server/display/DisplayDevice.java b/services/core/java/com/android/server/display/DisplayDevice.java
similarity index 97%
rename from services/java/com/android/server/display/DisplayDevice.java
rename to services/core/java/com/android/server/display/DisplayDevice.java
index 4161147..a5f9822 100644
--- a/services/java/com/android/server/display/DisplayDevice.java
+++ b/services/core/java/com/android/server/display/DisplayDevice.java
@@ -17,6 +17,7 @@
 package com.android.server.display;
 
 import android.graphics.Rect;
+import android.hardware.display.DisplayViewport;
 import android.os.IBinder;
 import android.view.Surface;
 import android.view.SurfaceControl;
@@ -106,15 +107,9 @@
     }
 
     /**
-     * Blanks the display, if supported.
+     * Sets the display state, if supported.
      */
-    public void blankLocked() {
-    }
-
-    /**
-     * Unblanks the display, if supported.
-     */
-    public void unblankLocked() {
+    public void requestDisplayStateLocked(int state) {
     }
 
     /**
diff --git a/services/java/com/android/server/display/DisplayDeviceInfo.java b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
similarity index 93%
rename from services/java/com/android/server/display/DisplayDeviceInfo.java
rename to services/core/java/com/android/server/display/DisplayDeviceInfo.java
index 11c5d87..a77443d 100644
--- a/services/java/com/android/server/display/DisplayDeviceInfo.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
@@ -16,6 +16,7 @@
 
 package com.android.server.display;
 
+import android.hardware.display.DisplayViewport;
 import android.util.DisplayMetrics;
 import android.view.Display;
 import android.view.Surface;
@@ -63,6 +64,7 @@
     /**
      * Flag: Indicates that the display device is owned by a particular application
      * and that no other application should be able to interact with it.
+     * Should typically be used together with {@link #FLAG_OWN_CONTENT_ONLY}.
      */
     public static final int FLAG_PRIVATE = 1 << 4;
 
@@ -78,6 +80,12 @@
     public static final int FLAG_PRESENTATION = 1 << 6;
 
     /**
+     * Flag: Only show this display's own content; do not mirror
+     * the content of another display.
+     */
+    public static final int FLAG_OWN_CONTENT_ONLY = 1 << 7;
+
+    /**
      * Touch attachment: Display does not receive touch.
      */
     public static final int TOUCH_NONE = 0;
@@ -168,6 +176,11 @@
     public String address;
 
     /**
+     * Display state.
+     */
+    public int state = Display.STATE_ON;
+
+    /**
      * The UID of the application that owns this display, or zero if it is owned by the system.
      * <p>
      * If the display is private, then only the owner can use it.
@@ -211,6 +224,7 @@
                 && rotation == other.rotation
                 && type == other.type
                 && Objects.equal(address, other.address)
+                && state == other.state
                 && ownerUid == other.ownerUid
                 && Objects.equal(ownerPackageName, other.ownerPackageName);
     }
@@ -233,6 +247,7 @@
         rotation = other.rotation;
         type = other.type;
         address = other.address;
+        state = other.state;
         ownerUid = other.ownerUid;
         ownerPackageName = other.ownerPackageName;
     }
@@ -252,6 +267,7 @@
         if (address != null) {
             sb.append(", address ").append(address);
         }
+        sb.append(", state ").append(Display.stateToString(state));
         if (ownerUid != 0 || ownerPackageName != null) {
             sb.append(", owner ").append(ownerPackageName);
             sb.append(" (uid ").append(ownerUid).append(")");
@@ -297,6 +313,9 @@
         if ((flags & FLAG_PRESENTATION) != 0) {
             msg.append(", FLAG_PRESENTATION");
         }
+        if ((flags & FLAG_OWN_CONTENT_ONLY) != 0) {
+            msg.append(", FLAG_OWN_CONTENT_ONLY");
+        }
         return msg.toString();
     }
 }
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
new file mode 100644
index 0000000..6697b60
--- /dev/null
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -0,0 +1,1392 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display;
+
+import com.android.internal.util.IndentingPrintWriter;
+
+import android.Manifest;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.hardware.SensorManager;
+import android.hardware.display.DisplayManager;
+import android.hardware.display.DisplayManagerGlobal;
+import android.hardware.display.DisplayManagerInternal;
+import android.hardware.display.DisplayViewport;
+import android.hardware.display.DisplayManagerInternal.DisplayTransactionListener;
+import android.hardware.display.IDisplayManager;
+import android.hardware.display.IDisplayManagerCallback;
+import android.hardware.display.WifiDisplayStatus;
+import android.hardware.input.InputManagerInternal;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.IBinder.DeathRecipient;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.os.SystemProperties;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.view.Display;
+import android.view.DisplayInfo;
+import android.view.Surface;
+import android.view.WindowManagerInternal;
+
+import com.android.server.DisplayThread;
+import com.android.server.LocalServices;
+import com.android.server.SystemService;
+import com.android.server.UiThread;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+/**
+ * Manages attached displays.
+ * <p>
+ * The {@link DisplayManagerService} manages the global lifecycle of displays,
+ * decides how to configure logical displays based on the physical display devices currently
+ * attached, sends notifications to the system and to applications when the state
+ * changes, and so on.
+ * </p><p>
+ * The display manager service relies on a collection of {@link DisplayAdapter} components,
+ * for discovering and configuring physical display devices attached to the system.
+ * There are separate display adapters for each manner that devices are attached:
+ * one display adapter for built-in local displays, one for simulated non-functional
+ * displays when the system is headless, one for simulated overlay displays used for
+ * development, one for wifi displays, etc.
+ * </p><p>
+ * Display adapters are only weakly coupled to the display manager service.
+ * Display adapters communicate changes in display device state to the display manager
+ * service asynchronously via a {@link DisplayAdapter.Listener} registered
+ * by the display manager service.  This separation of concerns is important for
+ * two main reasons.  First, it neatly encapsulates the responsibilities of these
+ * two classes: display adapters handle individual display devices whereas
+ * the display manager service handles the global state.  Second, it eliminates
+ * the potential for deadlocks resulting from asynchronous display device discovery.
+ * </p>
+ *
+ * <h3>Synchronization</h3>
+ * <p>
+ * Because the display manager may be accessed by multiple threads, the synchronization
+ * story gets a little complicated.  In particular, the window manager may call into
+ * the display manager while holding a surface transaction with the expectation that
+ * it can apply changes immediately.  Unfortunately, that means we can't just do
+ * everything asynchronously (*grump*).
+ * </p><p>
+ * To make this work, all of the objects that belong to the display manager must
+ * use the same lock.  We call this lock the synchronization root and it has a unique
+ * type {@link DisplayManagerService.SyncRoot}.  Methods that require this lock are
+ * named with the "Locked" suffix.
+ * </p><p>
+ * Where things get tricky is that the display manager is not allowed to make
+ * any potentially reentrant calls, especially into the window manager.  We generally
+ * avoid this by making all potentially reentrant out-calls asynchronous.
+ * </p>
+ */
+public final class DisplayManagerService extends SystemService {
+    private static final String TAG = "DisplayManagerService";
+    private static final boolean DEBUG = false;
+
+    // When this system property is set to 0, WFD is forcibly disabled on boot.
+    // When this system property is set to 1, WFD is forcibly enabled on boot.
+    // Otherwise WFD is enabled according to the value of config_enableWifiDisplay.
+    private static final String FORCE_WIFI_DISPLAY_ENABLE = "persist.debug.wfd.enable";
+
+    private static final long WAIT_FOR_DEFAULT_DISPLAY_TIMEOUT = 10000;
+
+    private static final int MSG_REGISTER_DEFAULT_DISPLAY_ADAPTER = 1;
+    private static final int MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS = 2;
+    private static final int MSG_DELIVER_DISPLAY_EVENT = 3;
+    private static final int MSG_REQUEST_TRAVERSAL = 4;
+    private static final int MSG_UPDATE_VIEWPORT = 5;
+
+    private final Context mContext;
+    private final DisplayManagerHandler mHandler;
+    private final Handler mUiHandler;
+    private final DisplayAdapterListener mDisplayAdapterListener;
+    private WindowManagerInternal mWindowManagerInternal;
+    private InputManagerInternal mInputManagerInternal;
+
+    // The synchronization root for the display manager.
+    // This lock guards most of the display manager's state.
+    // NOTE: This is synchronized on while holding WindowManagerService.mWindowMap so never call
+    // into WindowManagerService methods that require mWindowMap while holding this unless you are
+    // very very sure that no deadlock can occur.
+    private final SyncRoot mSyncRoot = new SyncRoot();
+
+    // True if in safe mode.
+    // This option may disable certain display adapters.
+    public boolean mSafeMode;
+
+    // True if we are in a special boot mode where only core applications and
+    // services should be started.  This option may disable certain display adapters.
+    public boolean mOnlyCore;
+
+    // True if the display manager service should pretend there is only one display
+    // and only tell applications about the existence of the default logical display.
+    // The display manager can still mirror content to secondary displays but applications
+    // cannot present unique content on those displays.
+    // Used for demonstration purposes only.
+    private final boolean mSingleDisplayDemoMode;
+
+    // All callback records indexed by calling process id.
+    public final SparseArray<CallbackRecord> mCallbacks =
+            new SparseArray<CallbackRecord>();
+
+    // List of all currently registered display adapters.
+    private final ArrayList<DisplayAdapter> mDisplayAdapters = new ArrayList<DisplayAdapter>();
+
+    // List of all currently connected display devices.
+    private final ArrayList<DisplayDevice> mDisplayDevices = new ArrayList<DisplayDevice>();
+
+    // List of all logical displays indexed by logical display id.
+    private final SparseArray<LogicalDisplay> mLogicalDisplays =
+            new SparseArray<LogicalDisplay>();
+    private int mNextNonDefaultDisplayId = Display.DEFAULT_DISPLAY + 1;
+
+    // List of all display transaction listeners.
+    private final CopyOnWriteArrayList<DisplayTransactionListener> mDisplayTransactionListeners =
+            new CopyOnWriteArrayList<DisplayTransactionListener>();
+
+    // Display power controller.
+    private DisplayPowerController mDisplayPowerController;
+
+    // The overall display state, independent of changes that might influence one
+    // display or another in particular.
+    private int mGlobalDisplayState = Display.STATE_UNKNOWN;
+
+    // Set to true when there are pending display changes that have yet to be applied
+    // to the surface flinger state.
+    private boolean mPendingTraversal;
+
+    // The Wifi display adapter, or null if not registered.
+    private WifiDisplayAdapter mWifiDisplayAdapter;
+
+    // The number of active wifi display scan requests.
+    private int mWifiDisplayScanRequestCount;
+
+    // The virtual display adapter, or null if not registered.
+    private VirtualDisplayAdapter mVirtualDisplayAdapter;
+
+    // Viewports of the default display and the display that should receive touch
+    // input from an external source.  Used by the input system.
+    private final DisplayViewport mDefaultViewport = new DisplayViewport();
+    private final DisplayViewport mExternalTouchViewport = new DisplayViewport();
+
+    // Persistent data store for all internal settings maintained by the display manager service.
+    private final PersistentDataStore mPersistentDataStore = new PersistentDataStore();
+
+    // Temporary callback list, used when sending display events to applications.
+    // May be used outside of the lock but only on the handler thread.
+    private final ArrayList<CallbackRecord> mTempCallbacks = new ArrayList<CallbackRecord>();
+
+    // Temporary display info, used for comparing display configurations.
+    private final DisplayInfo mTempDisplayInfo = new DisplayInfo();
+
+    // Temporary viewports, used when sending new viewport information to the
+    // input system.  May be used outside of the lock but only on the handler thread.
+    private final DisplayViewport mTempDefaultViewport = new DisplayViewport();
+    private final DisplayViewport mTempExternalTouchViewport = new DisplayViewport();
+
+    public DisplayManagerService(Context context) {
+        super(context);
+        mContext = context;
+        mHandler = new DisplayManagerHandler(DisplayThread.get().getLooper());
+        mUiHandler = UiThread.getHandler();
+        mDisplayAdapterListener = new DisplayAdapterListener();
+        mSingleDisplayDemoMode = SystemProperties.getBoolean("persist.demo.singledisplay", false);
+    }
+
+    @Override
+    public void onStart() {
+        mHandler.sendEmptyMessage(MSG_REGISTER_DEFAULT_DISPLAY_ADAPTER);
+
+        publishBinderService(Context.DISPLAY_SERVICE, new BinderService(),
+                true /*allowIsolated*/);
+        publishLocalService(DisplayManagerInternal.class, new LocalService());
+    }
+
+    @Override
+    public void onBootPhase(int phase) {
+        if (phase == PHASE_WAIT_FOR_DEFAULT_DISPLAY) {
+            synchronized (mSyncRoot) {
+                long timeout = SystemClock.uptimeMillis() + WAIT_FOR_DEFAULT_DISPLAY_TIMEOUT;
+                while (mLogicalDisplays.get(Display.DEFAULT_DISPLAY) == null) {
+                    long delay = timeout - SystemClock.uptimeMillis();
+                    if (delay <= 0) {
+                        throw new RuntimeException("Timeout waiting for default display "
+                                + "to be initialized.");
+                    }
+                    if (DEBUG) {
+                        Slog.d(TAG, "waitForDefaultDisplay: waiting, timeout=" + delay);
+                    }
+                    try {
+                        mSyncRoot.wait(delay);
+                    } catch (InterruptedException ex) {
+                    }
+                }
+            }
+        }
+    }
+
+    // TODO: Use dependencies or a boot phase
+    public void windowManagerAndInputReady() {
+        synchronized (mSyncRoot) {
+            mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
+            mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
+            scheduleTraversalLocked(false);
+        }
+    }
+
+    /**
+     * Called when the system is ready to go.
+     */
+    public void systemReady(boolean safeMode, boolean onlyCore) {
+        synchronized (mSyncRoot) {
+            mSafeMode = safeMode;
+            mOnlyCore = onlyCore;
+        }
+
+        mHandler.sendEmptyMessage(MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS);
+    }
+
+    private void registerDisplayTransactionListenerInternal(
+            DisplayTransactionListener listener) {
+        // List is self-synchronized copy-on-write.
+        mDisplayTransactionListeners.add(listener);
+    }
+
+    private void unregisterDisplayTransactionListenerInternal(
+            DisplayTransactionListener listener) {
+        // List is self-synchronized copy-on-write.
+        mDisplayTransactionListeners.remove(listener);
+    }
+
+    private void setDisplayInfoOverrideFromWindowManagerInternal(
+            int displayId, DisplayInfo info) {
+        synchronized (mSyncRoot) {
+            LogicalDisplay display = mLogicalDisplays.get(displayId);
+            if (display != null) {
+                if (display.setDisplayInfoOverrideFromWindowManagerLocked(info)) {
+                    sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_CHANGED);
+                    scheduleTraversalLocked(false);
+                }
+            }
+        }
+    }
+
+    private void performTraversalInTransactionFromWindowManagerInternal() {
+        synchronized (mSyncRoot) {
+            if (!mPendingTraversal) {
+                return;
+            }
+            mPendingTraversal = false;
+
+            performTraversalInTransactionLocked();
+        }
+
+        // List is self-synchronized copy-on-write.
+        for (DisplayTransactionListener listener : mDisplayTransactionListeners) {
+            listener.onDisplayTransaction();
+        }
+    }
+
+    private void requestGlobalDisplayStateInternal(int state) {
+        synchronized (mSyncRoot) {
+            if (mGlobalDisplayState != state) {
+                mGlobalDisplayState = state;
+                updateGlobalDisplayStateLocked();
+                scheduleTraversalLocked(false);
+            }
+        }
+    }
+
+    private DisplayInfo getDisplayInfoInternal(int displayId, int callingUid) {
+        synchronized (mSyncRoot) {
+            LogicalDisplay display = mLogicalDisplays.get(displayId);
+            if (display != null) {
+                DisplayInfo info = display.getDisplayInfoLocked();
+                if (info.hasAccess(callingUid)) {
+                    return info;
+                }
+            }
+            return null;
+        }
+    }
+
+    private int[] getDisplayIdsInternal(int callingUid) {
+        synchronized (mSyncRoot) {
+            final int count = mLogicalDisplays.size();
+            int[] displayIds = new int[count];
+            int n = 0;
+            for (int i = 0; i < count; i++) {
+                LogicalDisplay display = mLogicalDisplays.valueAt(i);
+                DisplayInfo info = display.getDisplayInfoLocked();
+                if (info.hasAccess(callingUid)) {
+                    displayIds[n++] = mLogicalDisplays.keyAt(i);
+                }
+            }
+            if (n != count) {
+                displayIds = Arrays.copyOfRange(displayIds, 0, n);
+            }
+            return displayIds;
+        }
+    }
+
+    private void registerCallbackInternal(IDisplayManagerCallback callback, int callingPid) {
+        synchronized (mSyncRoot) {
+            if (mCallbacks.get(callingPid) != null) {
+                throw new SecurityException("The calling process has already "
+                        + "registered an IDisplayManagerCallback.");
+            }
+
+            CallbackRecord record = new CallbackRecord(callingPid, callback);
+            try {
+                IBinder binder = callback.asBinder();
+                binder.linkToDeath(record, 0);
+            } catch (RemoteException ex) {
+                // give up
+                throw new RuntimeException(ex);
+            }
+
+            mCallbacks.put(callingPid, record);
+        }
+    }
+
+    private void onCallbackDied(CallbackRecord record) {
+        synchronized (mSyncRoot) {
+            mCallbacks.remove(record.mPid);
+            stopWifiDisplayScanLocked(record);
+        }
+    }
+
+    private void startWifiDisplayScanInternal(int callingPid) {
+        synchronized (mSyncRoot) {
+            CallbackRecord record = mCallbacks.get(callingPid);
+            if (record == null) {
+                throw new IllegalStateException("The calling process has not "
+                        + "registered an IDisplayManagerCallback.");
+            }
+            startWifiDisplayScanLocked(record);
+        }
+    }
+
+    private void startWifiDisplayScanLocked(CallbackRecord record) {
+        if (!record.mWifiDisplayScanRequested) {
+            record.mWifiDisplayScanRequested = true;
+            if (mWifiDisplayScanRequestCount++ == 0) {
+                if (mWifiDisplayAdapter != null) {
+                    mWifiDisplayAdapter.requestStartScanLocked();
+                }
+            }
+        }
+    }
+
+    private void stopWifiDisplayScanInternal(int callingPid) {
+        synchronized (mSyncRoot) {
+            CallbackRecord record = mCallbacks.get(callingPid);
+            if (record == null) {
+                throw new IllegalStateException("The calling process has not "
+                        + "registered an IDisplayManagerCallback.");
+            }
+            stopWifiDisplayScanLocked(record);
+        }
+    }
+
+    private void stopWifiDisplayScanLocked(CallbackRecord record) {
+        if (record.mWifiDisplayScanRequested) {
+            record.mWifiDisplayScanRequested = false;
+            if (--mWifiDisplayScanRequestCount == 0) {
+                if (mWifiDisplayAdapter != null) {
+                    mWifiDisplayAdapter.requestStopScanLocked();
+                }
+            } else if (mWifiDisplayScanRequestCount < 0) {
+                Log.wtf(TAG, "mWifiDisplayScanRequestCount became negative: "
+                        + mWifiDisplayScanRequestCount);
+                mWifiDisplayScanRequestCount = 0;
+            }
+        }
+    }
+
+    private void connectWifiDisplayInternal(String address) {
+        synchronized (mSyncRoot) {
+            if (mWifiDisplayAdapter != null) {
+                mWifiDisplayAdapter.requestConnectLocked(address);
+            }
+        }
+    }
+
+    private void pauseWifiDisplayInternal() {
+        synchronized (mSyncRoot) {
+            if (mWifiDisplayAdapter != null) {
+                mWifiDisplayAdapter.requestPauseLocked();
+            }
+        }
+    }
+
+    private void resumeWifiDisplayInternal() {
+        synchronized (mSyncRoot) {
+            if (mWifiDisplayAdapter != null) {
+                mWifiDisplayAdapter.requestResumeLocked();
+            }
+        }
+    }
+
+    private void disconnectWifiDisplayInternal() {
+        synchronized (mSyncRoot) {
+            if (mWifiDisplayAdapter != null) {
+                mWifiDisplayAdapter.requestDisconnectLocked();
+            }
+        }
+    }
+
+    private void renameWifiDisplayInternal(String address, String alias) {
+        synchronized (mSyncRoot) {
+            if (mWifiDisplayAdapter != null) {
+                mWifiDisplayAdapter.requestRenameLocked(address, alias);
+            }
+        }
+    }
+
+    private void forgetWifiDisplayInternal(String address) {
+        synchronized (mSyncRoot) {
+            if (mWifiDisplayAdapter != null) {
+                mWifiDisplayAdapter.requestForgetLocked(address);
+            }
+        }
+    }
+
+    private WifiDisplayStatus getWifiDisplayStatusInternal() {
+        synchronized (mSyncRoot) {
+            if (mWifiDisplayAdapter != null) {
+                return mWifiDisplayAdapter.getWifiDisplayStatusLocked();
+            }
+            return new WifiDisplayStatus();
+        }
+    }
+
+    private int createVirtualDisplayInternal(IBinder appToken, int callingUid, String packageName,
+            String name, int width, int height, int densityDpi, Surface surface, int flags) {
+        synchronized (mSyncRoot) {
+            if (mVirtualDisplayAdapter == null) {
+                Slog.w(TAG, "Rejecting request to create private virtual display "
+                        + "because the virtual display adapter is not available.");
+                return -1;
+            }
+
+            DisplayDevice device = mVirtualDisplayAdapter.createVirtualDisplayLocked(
+                    appToken, callingUid, packageName, name, width, height, densityDpi,
+                    surface, flags);
+            if (device == null) {
+                return -1;
+            }
+
+            handleDisplayDeviceAddedLocked(device);
+            LogicalDisplay display = findLogicalDisplayForDeviceLocked(device);
+            if (display != null) {
+                return display.getDisplayIdLocked();
+            }
+
+            // Something weird happened and the logical display was not created.
+            Slog.w(TAG, "Rejecting request to create virtual display "
+                    + "because the logical display was not created.");
+            mVirtualDisplayAdapter.releaseVirtualDisplayLocked(appToken);
+            handleDisplayDeviceRemovedLocked(device);
+        }
+        return -1;
+    }
+
+    private void setVirtualDisplaySurfaceInternal(IBinder appToken, Surface surface) {
+        synchronized (mSyncRoot) {
+            if (mVirtualDisplayAdapter == null) {
+                return;
+            }
+
+            mVirtualDisplayAdapter.setVirtualDisplaySurfaceLocked(appToken, surface);
+        }
+    }
+
+    private void releaseVirtualDisplayInternal(IBinder appToken) {
+        synchronized (mSyncRoot) {
+            if (mVirtualDisplayAdapter == null) {
+                return;
+            }
+
+            DisplayDevice device =
+                    mVirtualDisplayAdapter.releaseVirtualDisplayLocked(appToken);
+            if (device != null) {
+                handleDisplayDeviceRemovedLocked(device);
+            }
+        }
+    }
+
+    private void registerDefaultDisplayAdapter() {
+        // Register default display adapter.
+        synchronized (mSyncRoot) {
+            registerDisplayAdapterLocked(new LocalDisplayAdapter(
+                    mSyncRoot, mContext, mHandler, mDisplayAdapterListener));
+        }
+    }
+
+    private void registerAdditionalDisplayAdapters() {
+        synchronized (mSyncRoot) {
+            if (shouldRegisterNonEssentialDisplayAdaptersLocked()) {
+                registerOverlayDisplayAdapterLocked();
+                registerWifiDisplayAdapterLocked();
+                registerVirtualDisplayAdapterLocked();
+            }
+        }
+    }
+
+    private void registerOverlayDisplayAdapterLocked() {
+        registerDisplayAdapterLocked(new OverlayDisplayAdapter(
+                mSyncRoot, mContext, mHandler, mDisplayAdapterListener, mUiHandler));
+    }
+
+    private void registerWifiDisplayAdapterLocked() {
+        if (mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_enableWifiDisplay)
+                || SystemProperties.getInt(FORCE_WIFI_DISPLAY_ENABLE, -1) == 1) {
+            mWifiDisplayAdapter = new WifiDisplayAdapter(
+                    mSyncRoot, mContext, mHandler, mDisplayAdapterListener,
+                    mPersistentDataStore);
+            registerDisplayAdapterLocked(mWifiDisplayAdapter);
+        }
+    }
+
+    private void registerVirtualDisplayAdapterLocked() {
+        mVirtualDisplayAdapter = new VirtualDisplayAdapter(
+                mSyncRoot, mContext, mHandler, mDisplayAdapterListener);
+        registerDisplayAdapterLocked(mVirtualDisplayAdapter);
+    }
+
+    private boolean shouldRegisterNonEssentialDisplayAdaptersLocked() {
+        // In safe mode, we disable non-essential display adapters to give the user
+        // an opportunity to fix broken settings or other problems that might affect
+        // system stability.
+        // In only-core mode, we disable non-essential display adapters to minimize
+        // the number of dependencies that are started while in this mode and to
+        // prevent problems that might occur due to the device being encrypted.
+        return !mSafeMode && !mOnlyCore;
+    }
+
+    private void registerDisplayAdapterLocked(DisplayAdapter adapter) {
+        mDisplayAdapters.add(adapter);
+        adapter.registerLocked();
+    }
+
+    private void handleDisplayDeviceAdded(DisplayDevice device) {
+        synchronized (mSyncRoot) {
+            handleDisplayDeviceAddedLocked(device);
+        }
+    }
+
+    private void handleDisplayDeviceAddedLocked(DisplayDevice device) {
+        if (mDisplayDevices.contains(device)) {
+            Slog.w(TAG, "Attempted to add already added display device: "
+                    + device.getDisplayDeviceInfoLocked());
+            return;
+        }
+
+        Slog.i(TAG, "Display device added: " + device.getDisplayDeviceInfoLocked());
+
+        mDisplayDevices.add(device);
+        addLogicalDisplayLocked(device);
+        updateDisplayStateLocked(device);
+        scheduleTraversalLocked(false);
+    }
+
+    private void handleDisplayDeviceChanged(DisplayDevice device) {
+        synchronized (mSyncRoot) {
+            if (!mDisplayDevices.contains(device)) {
+                Slog.w(TAG, "Attempted to change non-existent display device: "
+                        + device.getDisplayDeviceInfoLocked());
+                return;
+            }
+
+            Slog.i(TAG, "Display device changed: " + device.getDisplayDeviceInfoLocked());
+
+            device.applyPendingDisplayDeviceInfoChangesLocked();
+            if (updateLogicalDisplaysLocked()) {
+                scheduleTraversalLocked(false);
+            }
+        }
+    }
+
+    private void handleDisplayDeviceRemoved(DisplayDevice device) {
+        synchronized (mSyncRoot) {
+            handleDisplayDeviceRemovedLocked(device);
+        }
+    }
+    private void handleDisplayDeviceRemovedLocked(DisplayDevice device) {
+        if (!mDisplayDevices.remove(device)) {
+            Slog.w(TAG, "Attempted to remove non-existent display device: "
+                    + device.getDisplayDeviceInfoLocked());
+            return;
+        }
+
+        Slog.i(TAG, "Display device removed: " + device.getDisplayDeviceInfoLocked());
+
+        updateLogicalDisplaysLocked();
+        scheduleTraversalLocked(false);
+    }
+
+    private void updateGlobalDisplayStateLocked() {
+        final int count = mDisplayDevices.size();
+        for (int i = 0; i < count; i++) {
+            DisplayDevice device = mDisplayDevices.get(i);
+            updateDisplayStateLocked(device);
+        }
+    }
+
+    private void updateDisplayStateLocked(DisplayDevice device) {
+        // Blank or unblank the display immediately to match the state requested
+        // by the display power controller (if known).
+        DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
+        if ((info.flags & DisplayDeviceInfo.FLAG_NEVER_BLANK) == 0) {
+            device.requestDisplayStateLocked(mGlobalDisplayState);
+        }
+    }
+
+    // Adds a new logical display based on the given display device.
+    // Sends notifications if needed.
+    private void addLogicalDisplayLocked(DisplayDevice device) {
+        DisplayDeviceInfo deviceInfo = device.getDisplayDeviceInfoLocked();
+        boolean isDefault = (deviceInfo.flags
+                & DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY) != 0;
+        if (isDefault && mLogicalDisplays.get(Display.DEFAULT_DISPLAY) != null) {
+            Slog.w(TAG, "Ignoring attempt to add a second default display: " + deviceInfo);
+            isDefault = false;
+        }
+
+        if (!isDefault && mSingleDisplayDemoMode) {
+            Slog.i(TAG, "Not creating a logical display for a secondary display "
+                    + " because single display demo mode is enabled: " + deviceInfo);
+            return;
+        }
+
+        final int displayId = assignDisplayIdLocked(isDefault);
+        final int layerStack = assignLayerStackLocked(displayId);
+
+        LogicalDisplay display = new LogicalDisplay(displayId, layerStack, device);
+        display.updateLocked(mDisplayDevices);
+        if (!display.isValidLocked()) {
+            // This should never happen currently.
+            Slog.w(TAG, "Ignoring display device because the logical display "
+                    + "created from it was not considered valid: " + deviceInfo);
+            return;
+        }
+
+        mLogicalDisplays.put(displayId, display);
+
+        // Wake up waitForDefaultDisplay.
+        if (isDefault) {
+            mSyncRoot.notifyAll();
+        }
+
+        sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_ADDED);
+    }
+
+    private int assignDisplayIdLocked(boolean isDefault) {
+        return isDefault ? Display.DEFAULT_DISPLAY : mNextNonDefaultDisplayId++;
+    }
+
+    private int assignLayerStackLocked(int displayId) {
+        // Currently layer stacks and display ids are the same.
+        // This need not be the case.
+        return displayId;
+    }
+
+    // Updates all existing logical displays given the current set of display devices.
+    // Removes invalid logical displays.
+    // Sends notifications if needed.
+    private boolean updateLogicalDisplaysLocked() {
+        boolean changed = false;
+        for (int i = mLogicalDisplays.size(); i-- > 0; ) {
+            final int displayId = mLogicalDisplays.keyAt(i);
+            LogicalDisplay display = mLogicalDisplays.valueAt(i);
+
+            mTempDisplayInfo.copyFrom(display.getDisplayInfoLocked());
+            display.updateLocked(mDisplayDevices);
+            if (!display.isValidLocked()) {
+                mLogicalDisplays.removeAt(i);
+                sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_REMOVED);
+                changed = true;
+            } else if (!mTempDisplayInfo.equals(display.getDisplayInfoLocked())) {
+                sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_CHANGED);
+                changed = true;
+            }
+        }
+        return changed;
+    }
+
+    private void performTraversalInTransactionLocked() {
+        // Clear all viewports before configuring displays so that we can keep
+        // track of which ones we have configured.
+        clearViewportsLocked();
+
+        // Configure each display device.
+        final int count = mDisplayDevices.size();
+        for (int i = 0; i < count; i++) {
+            DisplayDevice device = mDisplayDevices.get(i);
+            configureDisplayInTransactionLocked(device);
+            device.performTraversalInTransactionLocked();
+        }
+
+        // Tell the input system about these new viewports.
+        if (mInputManagerInternal != null) {
+            mHandler.sendEmptyMessage(MSG_UPDATE_VIEWPORT);
+        }
+    }
+
+    private void setDisplayHasContentInternal(int displayId, boolean hasContent,
+            boolean inTraversal) {
+        synchronized (mSyncRoot) {
+            LogicalDisplay display = mLogicalDisplays.get(displayId);
+            if (display != null && display.hasContentLocked() != hasContent) {
+                if (DEBUG) {
+                    Slog.d(TAG, "Display " + displayId + " hasContent flag changed: "
+                            + "hasContent=" + hasContent + ", inTraversal=" + inTraversal);
+                }
+
+                display.setHasContentLocked(hasContent);
+                scheduleTraversalLocked(inTraversal);
+            }
+        }
+    }
+
+    private void clearViewportsLocked() {
+        mDefaultViewport.valid = false;
+        mExternalTouchViewport.valid = false;
+    }
+
+    private void configureDisplayInTransactionLocked(DisplayDevice device) {
+        final DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
+        final boolean ownContent = (info.flags & DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY) != 0;
+
+        // Find the logical display that the display device is showing.
+        // Certain displays only ever show their own content.
+        LogicalDisplay display = findLogicalDisplayForDeviceLocked(device);
+        if (!ownContent) {
+            if (display != null && !display.hasContentLocked()) {
+                // If the display does not have any content of its own, then
+                // automatically mirror the default logical display contents.
+                display = null;
+            }
+            if (display == null) {
+                display = mLogicalDisplays.get(Display.DEFAULT_DISPLAY);
+            }
+        }
+
+        // Apply the logical display configuration to the display device.
+        if (display == null) {
+            // TODO: no logical display for the device, blank it
+            Slog.w(TAG, "Missing logical display to use for physical display device: "
+                    + device.getDisplayDeviceInfoLocked());
+            return;
+        }
+        display.configureDisplayInTransactionLocked(device, info.state == Display.STATE_OFF);
+
+        // Update the viewports if needed.
+        if (!mDefaultViewport.valid
+                && (info.flags & DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY) != 0) {
+            setViewportLocked(mDefaultViewport, display, device);
+        }
+        if (!mExternalTouchViewport.valid
+                && info.touch == DisplayDeviceInfo.TOUCH_EXTERNAL) {
+            setViewportLocked(mExternalTouchViewport, display, device);
+        }
+    }
+
+    private static void setViewportLocked(DisplayViewport viewport,
+            LogicalDisplay display, DisplayDevice device) {
+        viewport.valid = true;
+        viewport.displayId = display.getDisplayIdLocked();
+        device.populateViewportLocked(viewport);
+    }
+
+    private LogicalDisplay findLogicalDisplayForDeviceLocked(DisplayDevice device) {
+        final int count = mLogicalDisplays.size();
+        for (int i = 0; i < count; i++) {
+            LogicalDisplay display = mLogicalDisplays.valueAt(i);
+            if (display.getPrimaryDisplayDeviceLocked() == device) {
+                return display;
+            }
+        }
+        return null;
+    }
+
+    private void sendDisplayEventLocked(int displayId, int event) {
+        Message msg = mHandler.obtainMessage(MSG_DELIVER_DISPLAY_EVENT, displayId, event);
+        mHandler.sendMessage(msg);
+    }
+
+    // Requests that performTraversalsInTransactionFromWindowManager be called at a
+    // later time to apply changes to surfaces and displays.
+    private void scheduleTraversalLocked(boolean inTraversal) {
+        if (!mPendingTraversal && mWindowManagerInternal != null) {
+            mPendingTraversal = true;
+            if (!inTraversal) {
+                mHandler.sendEmptyMessage(MSG_REQUEST_TRAVERSAL);
+            }
+        }
+    }
+
+    // Runs on Handler thread.
+    // Delivers display event notifications to callbacks.
+    private void deliverDisplayEvent(int displayId, int event) {
+        if (DEBUG) {
+            Slog.d(TAG, "Delivering display event: displayId="
+                    + displayId + ", event=" + event);
+        }
+
+        // Grab the lock and copy the callbacks.
+        final int count;
+        synchronized (mSyncRoot) {
+            count = mCallbacks.size();
+            mTempCallbacks.clear();
+            for (int i = 0; i < count; i++) {
+                mTempCallbacks.add(mCallbacks.valueAt(i));
+            }
+        }
+
+        // After releasing the lock, send the notifications out.
+        for (int i = 0; i < count; i++) {
+            mTempCallbacks.get(i).notifyDisplayEventAsync(displayId, event);
+        }
+        mTempCallbacks.clear();
+    }
+
+    private void dumpInternal(PrintWriter pw) {
+        pw.println("DISPLAY MANAGER (dumpsys display)");
+
+        synchronized (mSyncRoot) {
+            pw.println("  mOnlyCode=" + mOnlyCore);
+            pw.println("  mSafeMode=" + mSafeMode);
+            pw.println("  mPendingTraversal=" + mPendingTraversal);
+            pw.println("  mGlobalDisplayState=" + Display.stateToString(mGlobalDisplayState));
+            pw.println("  mNextNonDefaultDisplayId=" + mNextNonDefaultDisplayId);
+            pw.println("  mDefaultViewport=" + mDefaultViewport);
+            pw.println("  mExternalTouchViewport=" + mExternalTouchViewport);
+            pw.println("  mSingleDisplayDemoMode=" + mSingleDisplayDemoMode);
+            pw.println("  mWifiDisplayScanRequestCount=" + mWifiDisplayScanRequestCount);
+
+            IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "    ");
+            ipw.increaseIndent();
+
+            pw.println();
+            pw.println("Display Adapters: size=" + mDisplayAdapters.size());
+            for (DisplayAdapter adapter : mDisplayAdapters) {
+                pw.println("  " + adapter.getName());
+                adapter.dumpLocked(ipw);
+            }
+
+            pw.println();
+            pw.println("Display Devices: size=" + mDisplayDevices.size());
+            for (DisplayDevice device : mDisplayDevices) {
+                pw.println("  " + device.getDisplayDeviceInfoLocked());
+                device.dumpLocked(ipw);
+            }
+
+            final int logicalDisplayCount = mLogicalDisplays.size();
+            pw.println();
+            pw.println("Logical Displays: size=" + logicalDisplayCount);
+            for (int i = 0; i < logicalDisplayCount; i++) {
+                int displayId = mLogicalDisplays.keyAt(i);
+                LogicalDisplay display = mLogicalDisplays.valueAt(i);
+                pw.println("  Display " + displayId + ":");
+                display.dumpLocked(ipw);
+            }
+
+            final int callbackCount = mCallbacks.size();
+            pw.println();
+            pw.println("Callbacks: size=" + callbackCount);
+            for (int i = 0; i < callbackCount; i++) {
+                CallbackRecord callback = mCallbacks.valueAt(i);
+                pw.println("  " + i + ": mPid=" + callback.mPid
+                        + ", mWifiDisplayScanRequested=" + callback.mWifiDisplayScanRequested);
+            }
+
+            if (mDisplayPowerController != null) {
+                mDisplayPowerController.dump(pw);
+            }
+        }
+    }
+
+    /**
+     * This is the object that everything in the display manager locks on.
+     * We make it an inner class within the {@link DisplayManagerService} to so that it is
+     * clear that the object belongs to the display manager service and that it is
+     * a unique object with a special purpose.
+     */
+    public static final class SyncRoot {
+    }
+
+    private final class DisplayManagerHandler extends Handler {
+        public DisplayManagerHandler(Looper looper) {
+            super(looper, null, true /*async*/);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_REGISTER_DEFAULT_DISPLAY_ADAPTER:
+                    registerDefaultDisplayAdapter();
+                    break;
+
+                case MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS:
+                    registerAdditionalDisplayAdapters();
+                    break;
+
+                case MSG_DELIVER_DISPLAY_EVENT:
+                    deliverDisplayEvent(msg.arg1, msg.arg2);
+                    break;
+
+                case MSG_REQUEST_TRAVERSAL:
+                    mWindowManagerInternal.requestTraversalFromDisplayManager();
+                    break;
+
+                case MSG_UPDATE_VIEWPORT: {
+                    synchronized (mSyncRoot) {
+                        mTempDefaultViewport.copyFrom(mDefaultViewport);
+                        mTempExternalTouchViewport.copyFrom(mExternalTouchViewport);
+                    }
+                    mInputManagerInternal.setDisplayViewports(
+                            mTempDefaultViewport, mTempExternalTouchViewport);
+                    break;
+                }
+            }
+        }
+    }
+
+    private final class DisplayAdapterListener implements DisplayAdapter.Listener {
+        @Override
+        public void onDisplayDeviceEvent(DisplayDevice device, int event) {
+            switch (event) {
+                case DisplayAdapter.DISPLAY_DEVICE_EVENT_ADDED:
+                    handleDisplayDeviceAdded(device);
+                    break;
+
+                case DisplayAdapter.DISPLAY_DEVICE_EVENT_CHANGED:
+                    handleDisplayDeviceChanged(device);
+                    break;
+
+                case DisplayAdapter.DISPLAY_DEVICE_EVENT_REMOVED:
+                    handleDisplayDeviceRemoved(device);
+                    break;
+            }
+        }
+
+        @Override
+        public void onTraversalRequested() {
+            synchronized (mSyncRoot) {
+                scheduleTraversalLocked(false);
+            }
+        }
+    }
+
+    private final class CallbackRecord implements DeathRecipient {
+        public final int mPid;
+        private final IDisplayManagerCallback mCallback;
+
+        public boolean mWifiDisplayScanRequested;
+
+        public CallbackRecord(int pid, IDisplayManagerCallback callback) {
+            mPid = pid;
+            mCallback = callback;
+        }
+
+        @Override
+        public void binderDied() {
+            if (DEBUG) {
+                Slog.d(TAG, "Display listener for pid " + mPid + " died.");
+            }
+            onCallbackDied(this);
+        }
+
+        public void notifyDisplayEventAsync(int displayId, int event) {
+            try {
+                mCallback.onDisplayEvent(displayId, event);
+            } catch (RemoteException ex) {
+                Slog.w(TAG, "Failed to notify process "
+                        + mPid + " that displays changed, assuming it died.", ex);
+                binderDied();
+            }
+        }
+    }
+
+    private final class BinderService extends IDisplayManager.Stub {
+        /**
+         * Returns information about the specified logical display.
+         *
+         * @param displayId The logical display id.
+         * @return The logical display info, or null if the display does not exist.  The
+         * returned object must be treated as immutable.
+         */
+        @Override // Binder call
+        public DisplayInfo getDisplayInfo(int displayId) {
+            final int callingUid = Binder.getCallingUid();
+            final long token = Binder.clearCallingIdentity();
+            try {
+                return getDisplayInfoInternal(displayId, callingUid);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        /**
+         * Returns the list of all display ids.
+         */
+        @Override // Binder call
+        public int[] getDisplayIds() {
+            final int callingUid = Binder.getCallingUid();
+            final long token = Binder.clearCallingIdentity();
+            try {
+                return getDisplayIdsInternal(callingUid);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override // Binder call
+        public void registerCallback(IDisplayManagerCallback callback) {
+            if (callback == null) {
+                throw new IllegalArgumentException("listener must not be null");
+            }
+
+            final int callingPid = Binder.getCallingPid();
+            final long token = Binder.clearCallingIdentity();
+            try {
+                registerCallbackInternal(callback, callingPid);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override // Binder call
+        public void startWifiDisplayScan() {
+            mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY,
+                    "Permission required to start wifi display scans");
+
+            final int callingPid = Binder.getCallingPid();
+            final long token = Binder.clearCallingIdentity();
+            try {
+                startWifiDisplayScanInternal(callingPid);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override // Binder call
+        public void stopWifiDisplayScan() {
+            mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY,
+                    "Permission required to stop wifi display scans");
+
+            final int callingPid = Binder.getCallingPid();
+            final long token = Binder.clearCallingIdentity();
+            try {
+                stopWifiDisplayScanInternal(callingPid);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override // Binder call
+        public void connectWifiDisplay(String address) {
+            if (address == null) {
+                throw new IllegalArgumentException("address must not be null");
+            }
+            mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY,
+                    "Permission required to connect to a wifi display");
+
+            final long token = Binder.clearCallingIdentity();
+            try {
+                connectWifiDisplayInternal(address);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override // Binder call
+        public void disconnectWifiDisplay() {
+            // This request does not require special permissions.
+            // Any app can request disconnection from the currently active wifi display.
+            // This exception should no longer be needed once wifi display control moves
+            // to the media router service.
+
+            final long token = Binder.clearCallingIdentity();
+            try {
+                disconnectWifiDisplayInternal();
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override // Binder call
+        public void renameWifiDisplay(String address, String alias) {
+            if (address == null) {
+                throw new IllegalArgumentException("address must not be null");
+            }
+            mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY,
+                    "Permission required to rename to a wifi display");
+
+            final long token = Binder.clearCallingIdentity();
+            try {
+                renameWifiDisplayInternal(address, alias);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override // Binder call
+        public void forgetWifiDisplay(String address) {
+            if (address == null) {
+                throw new IllegalArgumentException("address must not be null");
+            }
+            mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY,
+                    "Permission required to forget to a wifi display");
+
+            final long token = Binder.clearCallingIdentity();
+            try {
+                forgetWifiDisplayInternal(address);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override // Binder call
+        public void pauseWifiDisplay() {
+            mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY,
+                    "Permission required to pause a wifi display session");
+
+            final long token = Binder.clearCallingIdentity();
+            try {
+                pauseWifiDisplayInternal();
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override // Binder call
+        public void resumeWifiDisplay() {
+            mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY,
+                    "Permission required to resume a wifi display session");
+
+            final long token = Binder.clearCallingIdentity();
+            try {
+                resumeWifiDisplayInternal();
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override // Binder call
+        public WifiDisplayStatus getWifiDisplayStatus() {
+            // This request does not require special permissions.
+            // Any app can get information about available wifi displays.
+
+            final long token = Binder.clearCallingIdentity();
+            try {
+                return getWifiDisplayStatusInternal();
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override // Binder call
+        public int createVirtualDisplay(IBinder appToken, String packageName,
+                String name, int width, int height, int densityDpi, Surface surface, int flags) {
+            final int callingUid = Binder.getCallingUid();
+            if (!validatePackageName(callingUid, packageName)) {
+                throw new SecurityException("packageName must match the calling uid");
+            }
+            if (appToken == null) {
+                throw new IllegalArgumentException("appToken must not be null");
+            }
+            if (TextUtils.isEmpty(name)) {
+                throw new IllegalArgumentException("name must be non-null and non-empty");
+            }
+            if (width <= 0 || height <= 0 || densityDpi <= 0) {
+                throw new IllegalArgumentException("width, height, and densityDpi must be "
+                        + "greater than 0");
+            }
+            if (callingUid != Process.SYSTEM_UID &&
+                    (flags & DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC) != 0) {
+                if (mContext.checkCallingPermission(android.Manifest.permission.CAPTURE_VIDEO_OUTPUT)
+                        != PackageManager.PERMISSION_GRANTED
+                        && mContext.checkCallingPermission(
+                                android.Manifest.permission.CAPTURE_SECURE_VIDEO_OUTPUT)
+                                != PackageManager.PERMISSION_GRANTED) {
+                    throw new SecurityException("Requires CAPTURE_VIDEO_OUTPUT or "
+                            + "CAPTURE_SECURE_VIDEO_OUTPUT permission to create a "
+                            + "public virtual display.");
+                }
+            }
+            if ((flags & DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE) != 0) {
+                if (mContext.checkCallingPermission(
+                        android.Manifest.permission.CAPTURE_SECURE_VIDEO_OUTPUT)
+                        != PackageManager.PERMISSION_GRANTED) {
+                    throw new SecurityException("Requires CAPTURE_SECURE_VIDEO_OUTPUT "
+                            + "to create a secure virtual display.");
+                }
+            }
+
+            final long token = Binder.clearCallingIdentity();
+            try {
+                return createVirtualDisplayInternal(appToken, callingUid, packageName,
+                        name, width, height, densityDpi, surface, flags);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override // Binder call
+        public void setVirtualDisplaySurface(IBinder appToken, Surface surface) {
+            final long token = Binder.clearCallingIdentity();
+            try {
+                setVirtualDisplaySurfaceInternal(appToken, surface);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override // Binder call
+        public void releaseVirtualDisplay(IBinder appToken) {
+            final long token = Binder.clearCallingIdentity();
+            try {
+                releaseVirtualDisplayInternal(appToken);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override // Binder call
+        public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
+            if (mContext == null
+                    || mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP)
+                            != PackageManager.PERMISSION_GRANTED) {
+                pw.println("Permission Denial: can't dump DisplayManager from from pid="
+                        + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
+                return;
+            }
+
+            final long token = Binder.clearCallingIdentity();
+            try {
+                dumpInternal(pw);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        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;
+        }
+    }
+
+    private final class LocalService extends DisplayManagerInternal {
+        @Override
+        public void initPowerManagement(final DisplayPowerCallbacks callbacks, Handler handler,
+                SensorManager sensorManager) {
+            synchronized (mSyncRoot) {
+                DisplayBlanker blanker = new DisplayBlanker() {
+                    @Override
+                    public void requestDisplayState(int state) {
+                        // The order of operations is important for legacy reasons.
+                        if (state == Display.STATE_OFF) {
+                            requestGlobalDisplayStateInternal(state);
+                        }
+
+                        callbacks.onDisplayStateChange(state);
+
+                        if (state != Display.STATE_OFF) {
+                            requestGlobalDisplayStateInternal(state);
+                        }
+                    }
+                };
+                mDisplayPowerController = new DisplayPowerController(
+                        mContext, callbacks, handler, sensorManager, blanker);
+            }
+        }
+
+        @Override
+        public boolean requestPowerState(DisplayPowerRequest request,
+                boolean waitForNegativeProximity) {
+            return mDisplayPowerController.requestPowerState(request,
+                    waitForNegativeProximity);
+        }
+
+        @Override
+        public boolean isProximitySensorAvailable() {
+            return mDisplayPowerController.isProximitySensorAvailable();
+        }
+
+        @Override
+        public DisplayInfo getDisplayInfo(int displayId) {
+            return getDisplayInfoInternal(displayId, Process.myUid());
+        }
+
+        @Override
+        public void registerDisplayTransactionListener(DisplayTransactionListener listener) {
+            if (listener == null) {
+                throw new IllegalArgumentException("listener must not be null");
+            }
+
+            registerDisplayTransactionListenerInternal(listener);
+        }
+
+        @Override
+        public void unregisterDisplayTransactionListener(DisplayTransactionListener listener) {
+            if (listener == null) {
+                throw new IllegalArgumentException("listener must not be null");
+            }
+
+            unregisterDisplayTransactionListenerInternal(listener);
+        }
+
+        @Override
+        public void setDisplayInfoOverrideFromWindowManager(int displayId, DisplayInfo info) {
+            setDisplayInfoOverrideFromWindowManagerInternal(displayId, info);
+        }
+
+        @Override
+        public void performTraversalInTransactionFromWindowManager() {
+            performTraversalInTransactionFromWindowManagerInternal();
+        }
+
+        @Override
+        public void setDisplayHasContent(int displayId, boolean hasContent, boolean inTraversal) {
+            setDisplayHasContentInternal(displayId, hasContent, inTraversal);
+        }
+    }
+}
diff --git a/services/java/com/android/server/power/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
similarity index 91%
rename from services/java/com/android/server/power/DisplayPowerController.java
rename to services/core/java/com/android/server/display/DisplayPowerController.java
index 30bc922..279a9cc 100644
--- a/services/java/com/android/server/power/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -14,12 +14,15 @@
  * limitations under the License.
  */
 
-package com.android.server.power;
+package com.android.server.display;
 
-import com.android.server.LightsService;
-import com.android.server.TwilightService;
-import com.android.server.TwilightService.TwilightState;
-import com.android.server.display.DisplayManagerService;
+import com.android.internal.app.IBatteryStats;
+import com.android.server.LocalServices;
+import com.android.server.am.BatteryStatsService;
+import com.android.server.lights.LightsManager;
+import com.android.server.twilight.TwilightListener;
+import com.android.server.twilight.TwilightManager;
+import com.android.server.twilight.TwilightState;
 
 import android.animation.Animator;
 import android.animation.ObjectAnimator;
@@ -29,16 +32,20 @@
 import android.hardware.SensorEvent;
 import android.hardware.SensorEventListener;
 import android.hardware.SensorManager;
+import android.hardware.display.DisplayManagerInternal.DisplayPowerCallbacks;
+import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
 import android.os.PowerManager;
+import android.os.RemoteException;
 import android.os.SystemClock;
 import android.text.format.DateUtils;
 import android.util.FloatMath;
 import android.util.Slog;
 import android.util.Spline;
 import android.util.TimeUtils;
+import android.view.Display;
 
 import java.io.PrintWriter;
 
@@ -160,42 +167,37 @@
 
     private final Object mLock = new Object();
 
-    // Notifier for sending asynchronous notifications.
-    private final Notifier mNotifier;
-
-    // The display suspend blocker.
-    // Held while there are pending state change notifications.
-    private final SuspendBlocker mDisplaySuspendBlocker;
-
-    // The display blanker.
-    private final DisplayBlanker mDisplayBlanker;
-
     // Our handler.
     private final DisplayControllerHandler mHandler;
 
     // Asynchronous callbacks into the power manager service.
     // Only invoked from the handler thread while no locks are held.
-    private final Callbacks mCallbacks;
-    private Handler mCallbackHandler;
+    private final DisplayPowerCallbacks mCallbacks;
+
+    // Battery stats.
+    private final IBatteryStats mBatteryStats;
 
     // The lights service.
-    private final LightsService mLights;
+    private final LightsManager mLights;
 
     // The twilight service.
-    private final TwilightService mTwilight;
-
-    // The display manager.
-    private final DisplayManagerService mDisplayManager;
+    private final TwilightManager mTwilight;
 
     // The sensor manager.
     private final SensorManager mSensorManager;
 
+    // The display blanker.
+    private final DisplayBlanker mBlanker;
+
     // The proximity sensor, or null if not available or needed.
     private Sensor mProximitySensor;
 
     // The light sensor, or null if not available or needed.
     private Sensor mLightSensor;
 
+    // The doze screen brightness.
+    private final int mScreenBrightnessDozeConfig;
+
     // The dim screen brightness.
     private final int mScreenBrightnessDimConfig;
 
@@ -350,25 +352,23 @@
     /**
      * Creates the display power controller.
      */
-    public DisplayPowerController(Looper looper, Context context, Notifier notifier,
-            LightsService lights, TwilightService twilight, SensorManager sensorManager,
-            DisplayManagerService displayManager,
-            SuspendBlocker displaySuspendBlocker, DisplayBlanker displayBlanker,
-            Callbacks callbacks, Handler callbackHandler) {
-        mHandler = new DisplayControllerHandler(looper);
-        mNotifier = notifier;
-        mDisplaySuspendBlocker = displaySuspendBlocker;
-        mDisplayBlanker = displayBlanker;
+    public DisplayPowerController(Context context,
+            DisplayPowerCallbacks callbacks, Handler handler,
+            SensorManager sensorManager, DisplayBlanker blanker) {
+        mHandler = new DisplayControllerHandler(handler.getLooper());
         mCallbacks = callbacks;
-        mCallbackHandler = callbackHandler;
 
-        mLights = lights;
-        mTwilight = twilight;
+        mBatteryStats = BatteryStatsService.getService();
+        mLights = LocalServices.getService(LightsManager.class);
+        mTwilight = LocalServices.getService(TwilightManager.class);
         mSensorManager = sensorManager;
-        mDisplayManager = displayManager;
+        mBlanker = blanker;
 
         final Resources resources = context.getResources();
 
+        mScreenBrightnessDozeConfig = clampAbsoluteBrightness(resources.getInteger(
+                com.android.internal.R.integer.config_screenBrightnessDoze));
+
         mScreenBrightnessDimConfig = clampAbsoluteBrightness(resources.getInteger(
                 com.android.internal.R.integer.config_screenBrightnessDim));
 
@@ -526,9 +526,11 @@
     }
 
     private void initialize() {
-        mPowerState = new DisplayPowerState(
-                new ElectronBeam(mDisplayManager), mDisplayBlanker,
-                mLights.getLight(LightsService.LIGHT_ID_BACKLIGHT));
+        // Initialize the power state object for the default display.
+        // In the future, we might manage multiple displays independently.
+        mPowerState = new DisplayPowerState(mBlanker,
+                mLights.getLight(LightsManager.LIGHT_ID_BACKLIGHT),
+                new ElectronBeam(Display.DEFAULT_DISPLAY));
 
         mElectronBeamOnAnimator = ObjectAnimator.ofFloat(
                 mPowerState, DisplayPowerState.ELECTRON_BEAM_LEVEL, 0.0f, 1.0f);
@@ -542,6 +544,14 @@
 
         mScreenBrightnessRampAnimator = new RampAnimator<DisplayPowerState>(
                 mPowerState, DisplayPowerState.SCREEN_BRIGHTNESS);
+
+        // Initialize screen state for battery stats.
+        try {
+            mBatteryStats.noteScreenState(mPowerState.getScreenState());
+            mBatteryStats.noteScreenBrightness(mPowerState.getScreenBrightness());
+        } catch (RemoteException ex) {
+            // same process
+        }
     }
 
     private final Animator.AnimatorListener mAnimatorListener = new Animator.AnimatorListener() {
@@ -565,7 +575,7 @@
         final boolean mustNotify;
         boolean mustInitialize = false;
         boolean updateAutoBrightness = mTwilightChanged;
-        boolean wasDim = false;
+        boolean wasDimOrDoze = false;
         mTwilightChanged = false;
 
         synchronized (mLock) {
@@ -585,7 +595,8 @@
                         != mPendingRequestLocked.screenAutoBrightnessAdjustment) {
                     updateAutoBrightness = true;
                 }
-                wasDim = (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DIM);
+                wasDimOrDoze = (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DIM
+                        || mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DOZE);
                 mPowerRequest.copyFrom(mPendingRequestLocked);
                 mWaitingForNegativeProximity |= mPendingWaitForNegativeProximityLocked;
                 mPendingWaitForNegativeProximityLocked = false;
@@ -631,12 +642,12 @@
 
         // Turn on the light sensor if needed.
         if (mLightSensor != null) {
-            setLightSensorEnabled(mPowerRequest.useAutoBrightness
-                    && wantScreenOn(mPowerRequest.screenState), updateAutoBrightness);
+            setLightSensorEnabled(mPowerRequest.wantLightSensorEnabled(),
+                    updateAutoBrightness);
         }
 
         // Set the screen brightness.
-        if (wantScreenOn(mPowerRequest.screenState)) {
+        if (mPowerRequest.wantScreenOnAny()) {
             int target;
             boolean slow;
             if (mScreenAutoBrightness >= 0 && mLightSensorEnabled) {
@@ -653,12 +664,16 @@
                 slow = false;
                 mUsingScreenAutoBrightness = false;
             }
-            if (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DIM) {
+            if (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DOZE) {
+                // Dim quickly to the doze state.
+                target = mScreenBrightnessDozeConfig;
+                slow = false;
+            } else if (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DIM) {
                 // Dim quickly by at least some minimum amount.
                 target = Math.min(target - SCREEN_DIM_MINIMUM_REDUCTION,
                         mScreenBrightnessDimConfig);
                 slow = false;
-            } else if (wasDim) {
+            } else if (wasDimOrDoze) {
                 // Brighten quickly.
                 slow = false;
             }
@@ -672,9 +687,9 @@
         // Animate the screen on or off unless blocked.
         if (mScreenOffBecauseOfProximity) {
             // Screen off due to proximity.
-            setScreenOn(false);
+            setScreenState(Display.STATE_OFF);
             unblockScreenOn();
-        } else if (wantScreenOn(mPowerRequest.screenState)) {
+        } else if (mPowerRequest.wantScreenOnAny()) {
             // Want screen on.
             // Wait for previous off animation to complete beforehand.
             // It is relatively short but if we cancel it and switch to the
@@ -683,7 +698,8 @@
                 // Turn the screen on.  The contents of the screen may not yet
                 // be visible if the electron beam has not been dismissed because
                 // its last frame of animation is solid black.
-                setScreenOn(true);
+                setScreenState(mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DOZE
+                        ? Display.STATE_DOZING : Display.STATE_ON);
 
                 if (mPowerRequest.blockScreenOn
                         && mPowerState.getElectronBeamLevel() == 0.0f) {
@@ -716,12 +732,12 @@
             if (!mElectronBeamOnAnimator.isStarted()) {
                 if (!mElectronBeamOffAnimator.isStarted()) {
                     if (mPowerState.getElectronBeamLevel() == 0.0f) {
-                        setScreenOn(false);
+                        setScreenState(Display.STATE_OFF);
                     } else if (mPowerState.prepareElectronBeam(
                             mElectronBeamFadesConfig ?
                                     ElectronBeam.MODE_FADE :
                                             ElectronBeam.MODE_COOL_DOWN)
-                            && mPowerState.isScreenOn()) {
+                            && mPowerState.getScreenState() != Display.STATE_OFF) {
                         mElectronBeamOffAnimator.start();
                     } else {
                         mElectronBeamOffAnimator.end();
@@ -754,9 +770,9 @@
     private void blockScreenOn() {
         if (!mScreenOnWasBlocked) {
             mScreenOnWasBlocked = true;
+            mScreenOnBlockStartRealTime = SystemClock.elapsedRealtime();
             if (DEBUG) {
                 Slog.d(TAG, "Blocked screen on.");
-                mScreenOnBlockStartRealTime = SystemClock.elapsedRealtime();
             }
         }
     }
@@ -771,13 +787,13 @@
         }
     }
 
-    private void setScreenOn(boolean on) {
-        if (mPowerState.isScreenOn() != on) {
-            mPowerState.setScreenOn(on);
-            if (on) {
-                mNotifier.onScreenOn();
-            } else {
-                mNotifier.onScreenOff();
+    private void setScreenState(int state) {
+        if (mPowerState.getScreenState() != state) {
+            mPowerState.setScreenState(state);
+            try {
+                mBatteryStats.noteScreenState(state);
+            } catch (RemoteException ex) {
+                // same process
             }
         }
     }
@@ -806,7 +822,11 @@
 
     private void animateScreenBrightness(int target, int rate) {
         if (mScreenBrightnessRampAnimator.animateTo(target, rate)) {
-            mNotifier.onScreenBrightness(target);
+            try {
+                mBatteryStats.noteScreenBrightness(target);
+            } catch (RemoteException ex) {
+                // same process
+            }
         }
     }
 
@@ -891,13 +911,13 @@
     private void clearPendingProximityDebounceTime() {
         if (mPendingProximityDebounceTime >= 0) {
             mPendingProximityDebounceTime = -1;
-            mDisplaySuspendBlocker.release(); // release wake lock
+            mCallbacks.releaseSuspendBlocker(); // release wake lock
         }
     }
 
     private void setPendingProximityDebounceTime(long debounceTime) {
         if (mPendingProximityDebounceTime < 0) {
-            mDisplaySuspendBlocker.acquire(); // acquire wake lock
+            mCallbacks.acquireSuspendBlocker(); // acquire wake lock
         }
         mPendingProximityDebounceTime = debounceTime;
     }
@@ -1167,48 +1187,48 @@
     }
 
     private void sendOnStateChangedWithWakelock() {
-        mDisplaySuspendBlocker.acquire();
-        mCallbackHandler.post(mOnStateChangedRunnable);
+        mCallbacks.acquireSuspendBlocker();
+        mHandler.post(mOnStateChangedRunnable);
     }
 
     private final Runnable mOnStateChangedRunnable = new Runnable() {
         @Override
         public void run() {
             mCallbacks.onStateChanged();
-            mDisplaySuspendBlocker.release();
+            mCallbacks.releaseSuspendBlocker();
         }
     };
 
     private void sendOnProximityPositiveWithWakelock() {
-        mDisplaySuspendBlocker.acquire();
-        mCallbackHandler.post(mOnProximityPositiveRunnable);
+        mCallbacks.acquireSuspendBlocker();
+        mHandler.post(mOnProximityPositiveRunnable);
     }
 
     private final Runnable mOnProximityPositiveRunnable = new Runnable() {
         @Override
         public void run() {
             mCallbacks.onProximityPositive();
-            mDisplaySuspendBlocker.release();
+            mCallbacks.releaseSuspendBlocker();
         }
     };
 
     private void sendOnProximityNegativeWithWakelock() {
-        mDisplaySuspendBlocker.acquire();
-        mCallbackHandler.post(mOnProximityNegativeRunnable);
+        mCallbacks.acquireSuspendBlocker();
+        mHandler.post(mOnProximityNegativeRunnable);
     }
 
     private final Runnable mOnProximityNegativeRunnable = new Runnable() {
         @Override
         public void run() {
             mCallbacks.onProximityNegative();
-            mDisplaySuspendBlocker.release();
+            mCallbacks.releaseSuspendBlocker();
         }
     };
 
     public void dump(final PrintWriter pw) {
         synchronized (mLock) {
             pw.println();
-            pw.println("Display Controller Locked State:");
+            pw.println("Display Power Controller Locked State:");
             pw.println("  mDisplayReadyLocked=" + mDisplayReadyLocked);
             pw.println("  mPendingRequestLocked=" + mPendingRequestLocked);
             pw.println("  mPendingRequestChangedLocked=" + mPendingRequestChangedLocked);
@@ -1218,7 +1238,8 @@
         }
 
         pw.println();
-        pw.println("Display Controller Configuration:");
+        pw.println("Display Power Controller Configuration:");
+        pw.println("  mScreenBrightnessDozeConfig=" + mScreenBrightnessDozeConfig);
         pw.println("  mScreenBrightnessDimConfig=" + mScreenBrightnessDimConfig);
         pw.println("  mScreenBrightnessRangeMinimum=" + mScreenBrightnessRangeMinimum);
         pw.println("  mScreenBrightnessRangeMaximum=" + mScreenBrightnessRangeMaximum);
@@ -1237,7 +1258,7 @@
 
     private void dumpLocal(PrintWriter pw) {
         pw.println();
-        pw.println("Display Controller Thread State:");
+        pw.println("Display Power Controller Thread State:");
         pw.println("  mPowerRequest=" + mPowerRequest);
         pw.println("  mWaitingForNegativeProximity=" + mWaitingForNegativeProximity);
 
@@ -1296,24 +1317,6 @@
         }
     }
 
-    private static boolean wantScreenOn(int state) {
-        switch (state) {
-            case DisplayPowerRequest.SCREEN_STATE_BRIGHT:
-            case DisplayPowerRequest.SCREEN_STATE_DIM:
-                return true;
-        }
-        return false;
-    }
-
-    /**
-     * Asynchronous callbacks from the power controller to the power manager service.
-     */
-    public interface Callbacks {
-        void onStateChanged();
-        void onProximityPositive();
-        void onProximityNegative();
-    }
-
     private final class DisplayControllerHandler extends Handler {
         public DisplayControllerHandler(Looper looper) {
             super(looper, null, true /*async*/);
@@ -1370,8 +1373,7 @@
         }
     };
 
-    private final TwilightService.TwilightListener mTwilightListener =
-            new TwilightService.TwilightListener() {
+    private final TwilightListener mTwilightListener = new TwilightListener() {
         @Override
         public void onTwilightStateChanged() {
             mTwilightChanged = true;
diff --git a/services/java/com/android/server/power/DisplayPowerState.java b/services/core/java/com/android/server/display/DisplayPowerState.java
similarity index 81%
rename from services/java/com/android/server/power/DisplayPowerState.java
rename to services/core/java/com/android/server/display/DisplayPowerState.java
index 5c048f1..a5f8849 100644
--- a/services/java/com/android/server/power/DisplayPowerState.java
+++ b/services/core/java/com/android/server/display/DisplayPowerState.java
@@ -14,9 +14,9 @@
  * limitations under the License.
  */
 
-package com.android.server.power;
+package com.android.server.display;
 
-import com.android.server.LightsService;
+import com.android.server.lights.Light;
 
 import android.os.AsyncTask;
 import android.os.Handler;
@@ -26,14 +26,15 @@
 import android.util.IntProperty;
 import android.util.Slog;
 import android.view.Choreographer;
+import android.view.Display;
 
 import java.io.PrintWriter;
 
 /**
  * Controls the display power state.
  * <p>
- * This component is similar in nature to a {@link View} except that it describes
- * the properties of a display.  When properties are changed, the component
+ * This component is similar in nature to a {@link android.view.View} except that it
+ * describes the properties of a display.  When properties are changed, the component
  * invalidates itself and posts a callback to apply the changes in a consistent order.
  * This mechanism enables multiple properties of the display power state to be animated
  * together smoothly by the animation framework.  Some of the work to blank or unblank
@@ -43,8 +44,7 @@
  * that belongs to the {@link DisplayPowerController}.
  * </p><p>
  * We don't need to worry about holding a suspend blocker here because the
- * {@link PowerManagerService} does that for us whenever there is a change
- * in progress.
+ * power manager does that for us whenever there is a change in progress.
  * </p>
  */
 final class DisplayPowerState {
@@ -54,12 +54,12 @@
 
     private final Handler mHandler;
     private final Choreographer mChoreographer;
+    private final DisplayBlanker mBlanker;
+    private final Light mBacklight;
     private final ElectronBeam mElectronBeam;
-    private final DisplayBlanker mDisplayBlanker;
-    private final LightsService.Light mBacklight;
     private final PhotonicModulator mPhotonicModulator;
 
-    private boolean mScreenOn;
+    private int mScreenState;
     private int mScreenBrightness;
     private boolean mScreenReady;
     private boolean mScreenUpdatePending;
@@ -71,13 +71,12 @@
 
     private Runnable mCleanListener;
 
-    public DisplayPowerState(ElectronBeam electronBean,
-            DisplayBlanker displayBlanker, LightsService.Light backlight) {
+    public DisplayPowerState(DisplayBlanker blanker, Light backlight, ElectronBeam electronBeam) {
         mHandler = new Handler(true /*async*/);
         mChoreographer = Choreographer.getInstance();
-        mElectronBeam = electronBean;
-        mDisplayBlanker = displayBlanker;
+        mBlanker = blanker;
         mBacklight = backlight;
+        mElectronBeam = electronBeam;
         mPhotonicModulator = new PhotonicModulator();
 
         // At boot time, we know that the screen is on and the electron beam
@@ -86,7 +85,7 @@
         // Although we set the brightness to full on here, the display power controller
         // will reset the brightness to a new level immediately before the changes
         // actually have a chance to be applied.
-        mScreenOn = true;
+        mScreenState = Display.STATE_ON;
         mScreenBrightness = PowerManager.BRIGHTNESS_ON;
         scheduleScreenUpdate();
 
@@ -122,25 +121,25 @@
     };
 
     /**
-     * Sets whether the screen is on or off.
+     * Sets whether the screen is on, off, or dozing.
      */
-    public void setScreenOn(boolean on) {
-        if (mScreenOn != on) {
+    public void setScreenState(int state) {
+        if (mScreenState != state) {
             if (DEBUG) {
-                Slog.d(TAG, "setScreenOn: on=" + on);
+                Slog.d(TAG, "setScreenState: state=" + state);
             }
 
-            mScreenOn = on;
+            mScreenState = state;
             mScreenReady = false;
             scheduleScreenUpdate();
         }
     }
 
     /**
-     * Returns true if the screen is on.
+     * Gets the desired screen state.
      */
-    public boolean isScreenOn() {
-        return mScreenOn;
+    public int getScreenState() {
+        return mScreenState;
     }
 
     /**
@@ -155,7 +154,7 @@
             }
 
             mScreenBrightness = brightness;
-            if (mScreenOn) {
+            if (mScreenState != Display.STATE_OFF) {
                 mScreenReady = false;
                 scheduleScreenUpdate();
             }
@@ -219,7 +218,7 @@
             }
 
             mElectronBeamLevel = level;
-            if (mScreenOn) {
+            if (mScreenState != Display.STATE_OFF) {
                 mScreenReady = false;
                 scheduleScreenUpdate(); // update backlight brightness
             }
@@ -256,7 +255,7 @@
     public void dump(PrintWriter pw) {
         pw.println();
         pw.println("Display Power State:");
-        pw.println("  mScreenOn=" + mScreenOn);
+        pw.println("  mScreenState=" + Display.stateToString(mScreenState));
         pw.println("  mScreenBrightness=" + mScreenBrightness);
         pw.println("  mScreenReady=" + mScreenReady);
         pw.println("  mScreenUpdatePending=" + mScreenUpdatePending);
@@ -302,8 +301,9 @@
         public void run() {
             mScreenUpdatePending = false;
 
-            int brightness = mScreenOn && mElectronBeamLevel > 0f ? mScreenBrightness : 0;
-            if (mPhotonicModulator.setState(mScreenOn, brightness)) {
+            int brightness = mScreenState != Display.STATE_OFF
+                    && mElectronBeamLevel > 0f ? mScreenBrightness : 0;
+            if (mPhotonicModulator.setState(mScreenState, brightness)) {
                 if (DEBUG) {
                     Slog.d(TAG, "Screen ready");
                 }
@@ -335,26 +335,26 @@
      * Updates the state of the screen and backlight asynchronously on a separate thread.
      */
     private final class PhotonicModulator {
-        private static final boolean INITIAL_SCREEN_ON = false; // unknown, assume off
+        private static final int INITIAL_SCREEN_STATE = Display.STATE_OFF; // unknown, assume off
         private static final int INITIAL_BACKLIGHT = -1; // unknown
 
         private final Object mLock = new Object();
 
-        private boolean mPendingOn = INITIAL_SCREEN_ON;
+        private int mPendingState = INITIAL_SCREEN_STATE;
         private int mPendingBacklight = INITIAL_BACKLIGHT;
-        private boolean mActualOn = INITIAL_SCREEN_ON;
+        private int mActualState = INITIAL_SCREEN_STATE;
         private int mActualBacklight = INITIAL_BACKLIGHT;
         private boolean mChangeInProgress;
 
-        public boolean setState(boolean on, int backlight) {
+        public boolean setState(int state, int backlight) {
             synchronized (mLock) {
-                if (on != mPendingOn || backlight != mPendingBacklight) {
+                if (state != mPendingState || backlight != mPendingBacklight) {
                     if (DEBUG) {
-                        Slog.d(TAG, "Requesting new screen state: on=" + on
-                                + ", backlight=" + backlight);
+                        Slog.d(TAG, "Requesting new screen state: state="
+                                + Display.stateToString(state) + ", backlight=" + backlight);
                     }
 
-                    mPendingOn = on;
+                    mPendingState = state;
                     mPendingBacklight = backlight;
 
                     if (!mChangeInProgress) {
@@ -369,9 +369,9 @@
         public void dump(PrintWriter pw) {
             pw.println();
             pw.println("Photonic Modulator State:");
-            pw.println("  mPendingOn=" + mPendingOn);
+            pw.println("  mPendingState=" + Display.stateToString(mPendingState));
             pw.println("  mPendingBacklight=" + mPendingBacklight);
-            pw.println("  mActualOn=" + mActualOn);
+            pw.println("  mActualState=" + Display.stateToString(mActualState));
             pw.println("  mActualBacklight=" + mActualBacklight);
             pw.println("  mChangeInProgress=" + mChangeInProgress);
         }
@@ -381,35 +381,35 @@
             public void run() {
                 // Apply pending changes until done.
                 for (;;) {
-                    final boolean on;
-                    final boolean onChanged;
+                    final int state;
+                    final boolean stateChanged;
                     final int backlight;
                     final boolean backlightChanged;
                     synchronized (mLock) {
-                        on = mPendingOn;
-                        onChanged = (on != mActualOn);
+                        state = mPendingState;
+                        stateChanged = (state != mActualState);
                         backlight = mPendingBacklight;
                         backlightChanged = (backlight != mActualBacklight);
-                        if (!onChanged && !backlightChanged) {
+                        if (!stateChanged && !backlightChanged) {
                             mChangeInProgress = false;
                             break;
                         }
-                        mActualOn = on;
+                        mActualState = state;
                         mActualBacklight = backlight;
                     }
 
                     if (DEBUG) {
-                        Slog.d(TAG, "Updating screen state: on=" + on
-                                + ", backlight=" + backlight);
+                        Slog.d(TAG, "Updating screen state: state="
+                                + Display.stateToString(state) + ", backlight=" + backlight);
                     }
-                    if (onChanged && on) {
-                        mDisplayBlanker.unblankAllDisplays();
+                    if (stateChanged && state != Display.STATE_OFF) {
+                        mBlanker.requestDisplayState(state);
                     }
                     if (backlightChanged) {
                         mBacklight.setBrightness(backlight);
                     }
-                    if (onChanged && !on) {
-                        mDisplayBlanker.blankAllDisplays();
+                    if (stateChanged && state == Display.STATE_OFF) {
+                        mBlanker.requestDisplayState(state);
                     }
                 }
 
diff --git a/services/java/com/android/server/power/ElectronBeam.java b/services/core/java/com/android/server/display/ElectronBeam.java
similarity index 95%
rename from services/java/com/android/server/power/ElectronBeam.java
rename to services/core/java/com/android/server/display/ElectronBeam.java
index 729bd16..18e4049 100644
--- a/services/java/com/android/server/power/ElectronBeam.java
+++ b/services/core/java/com/android/server/display/ElectronBeam.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.power;
+package com.android.server.display;
 
 import java.io.PrintWriter;
 import java.nio.ByteBuffer;
@@ -23,6 +23,8 @@
 
 import android.graphics.PixelFormat;
 import android.graphics.SurfaceTexture;
+import android.hardware.display.DisplayManagerInternal;
+import android.hardware.display.DisplayManagerInternal.DisplayTransactionListener;
 import android.opengl.EGL14;
 import android.opengl.EGLConfig;
 import android.opengl.EGLContext;
@@ -33,15 +35,13 @@
 import android.os.Looper;
 import android.util.FloatMath;
 import android.util.Slog;
-import android.view.Display;
 import android.view.DisplayInfo;
 import android.view.Surface.OutOfResourcesException;
 import android.view.Surface;
 import android.view.SurfaceControl;
 import android.view.SurfaceSession;
 
-import com.android.server.display.DisplayManagerService;
-import com.android.server.display.DisplayTransactionListener;
+import com.android.server.LocalServices;
 
 /**
  * Bzzzoooop!  *crackle*
@@ -73,11 +73,13 @@
     // See code for details.
     private static final int DEJANK_FRAMES = 3;
 
+    private final int mDisplayId;
+
     // Set to true when the animation context has been fully prepared.
     private boolean mPrepared;
     private int mMode;
 
-    private final DisplayManagerService mDisplayManager;
+    private final DisplayManagerInternal mDisplayManagerInternal;
     private int mDisplayLayerStack; // layer stack associated with primary display
     private int mDisplayWidth;      // real width, not rotated
     private int mDisplayHeight;     // real height, not rotated
@@ -117,9 +119,9 @@
      */
     public static final int MODE_FADE = 2;
 
-
-    public ElectronBeam(DisplayManagerService displayManager) {
-        mDisplayManager = displayManager;
+    public ElectronBeam(int displayId) {
+        mDisplayId = displayId;
+        mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
     }
 
     /**
@@ -138,7 +140,7 @@
 
         // Get the display size and layer stack.
         // This is not expected to change while the electron beam surface is showing.
-        DisplayInfo displayInfo = mDisplayManager.getDisplayInfo(Display.DEFAULT_DISPLAY);
+        DisplayInfo displayInfo = mDisplayManagerInternal.getDisplayInfo(mDisplayId);
         mDisplayLayerStack = displayInfo.layerStack;
         mDisplayWidth = displayInfo.getNaturalWidth();
         mDisplayHeight = displayInfo.getNaturalHeight();
@@ -527,7 +529,8 @@
             mSurface = new Surface();
             mSurface.copyFrom(mSurfaceControl);
 
-            mSurfaceLayout = new NaturalSurfaceLayout(mDisplayManager, mSurfaceControl);
+            mSurfaceLayout = new NaturalSurfaceLayout(mDisplayManagerInternal,
+                    mDisplayId, mSurfaceControl);
             mSurfaceLayout.onDisplayTransaction();
         } finally {
             SurfaceControl.closeTransaction();
@@ -685,20 +688,23 @@
      * owns the electron beam.
      */
     private static final class NaturalSurfaceLayout implements DisplayTransactionListener {
-        private final DisplayManagerService mDisplayManager;
+        private final DisplayManagerInternal mDisplayManagerInternal;
+        private final int mDisplayId;
         private SurfaceControl mSurfaceControl;
 
-        public NaturalSurfaceLayout(DisplayManagerService displayManager, SurfaceControl surfaceControl) {
-            mDisplayManager = displayManager;
+        public NaturalSurfaceLayout(DisplayManagerInternal displayManagerInternal,
+                int displayId, SurfaceControl surfaceControl) {
+            mDisplayManagerInternal = displayManagerInternal;
+            mDisplayId = displayId;
             mSurfaceControl = surfaceControl;
-            mDisplayManager.registerDisplayTransactionListener(this);
+            mDisplayManagerInternal.registerDisplayTransactionListener(this);
         }
 
         public void dispose() {
             synchronized (this) {
                 mSurfaceControl = null;
             }
-            mDisplayManager.unregisterDisplayTransactionListener(this);
+            mDisplayManagerInternal.unregisterDisplayTransactionListener(this);
         }
 
         @Override
@@ -708,7 +714,7 @@
                     return;
                 }
 
-                DisplayInfo displayInfo = mDisplayManager.getDisplayInfo(Display.DEFAULT_DISPLAY);
+                DisplayInfo displayInfo = mDisplayManagerInternal.getDisplayInfo(mDisplayId);
                 switch (displayInfo.rotation) {
                     case Surface.ROTATION_0:
                         mSurfaceControl.setPosition(0, 0);
diff --git a/services/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
similarity index 88%
rename from services/java/com/android/server/display/LocalDisplayAdapter.java
rename to services/core/java/com/android/server/display/LocalDisplayAdapter.java
index cb8f3e2..096f263 100644
--- a/services/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -96,13 +96,21 @@
         }
     }
 
+    static boolean shouldBlank(int state) {
+        return state == Display.STATE_OFF;
+    }
+
+    static boolean shouldUnblank(int state) {
+        return state == Display.STATE_ON || state == Display.STATE_DOZING;
+    }
+
     private final class LocalDisplayDevice extends DisplayDevice {
         private final int mBuiltInDisplayId;
         private final SurfaceControl.PhysicalDisplayInfo mPhys;
 
         private DisplayDeviceInfo mInfo;
         private boolean mHavePendingChanges;
-        private boolean mBlanked;
+        private int mState = Display.STATE_UNKNOWN;
 
         public LocalDisplayDevice(IBinder displayToken, int builtInDisplayId,
                 SurfaceControl.PhysicalDisplayInfo phys) {
@@ -135,6 +143,7 @@
                 mInfo.width = mPhys.width;
                 mInfo.height = mPhys.height;
                 mInfo.refreshRate = mPhys.refreshRate;
+                mInfo.state = mState;
 
                 // Assume that all built-in displays that have secure output (eg. HDCP) also
                 // support compositing from gralloc protected buffers.
@@ -172,15 +181,16 @@
         }
 
         @Override
-        public void blankLocked() {
-            mBlanked = true;
-            SurfaceControl.blankDisplay(getDisplayTokenLocked());
-        }
-
-        @Override
-        public void unblankLocked() {
-            mBlanked = false;
-            SurfaceControl.unblankDisplay(getDisplayTokenLocked());
+        public void requestDisplayStateLocked(int state) {
+            if (mState != state) {
+                if (shouldBlank(state) && !shouldBlank(mState)) {
+                    SurfaceControl.blankDisplay(getDisplayTokenLocked());
+                } else if (shouldUnblank(state) && !shouldUnblank(mState)) {
+                    SurfaceControl.unblankDisplay(getDisplayTokenLocked());
+                }
+                mState = state;
+                updateDeviceInfoLocked();
+            }
         }
 
         @Override
@@ -188,7 +198,12 @@
             super.dumpLocked(pw);
             pw.println("mBuiltInDisplayId=" + mBuiltInDisplayId);
             pw.println("mPhys=" + mPhys);
-            pw.println("mBlanked=" + mBlanked);
+            pw.println("mState=" + Display.stateToString(mState));
+        }
+
+        private void updateDeviceInfoLocked() {
+            mInfo = null;
+            sendDisplayDeviceEventLocked(this, DISPLAY_DEVICE_EVENT_CHANGED);
         }
     }
 
diff --git a/services/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
similarity index 98%
rename from services/java/com/android/server/display/LogicalDisplay.java
rename to services/core/java/com/android/server/display/LogicalDisplay.java
index 7e357c0..5499af6 100644
--- a/services/java/com/android/server/display/LogicalDisplay.java
+++ b/services/core/java/com/android/server/display/LogicalDisplay.java
@@ -114,6 +114,7 @@
                 mInfo.copyFrom(mOverrideDisplayInfo);
                 mInfo.layerStack = mBaseDisplayInfo.layerStack;
                 mInfo.name = mBaseDisplayInfo.name;
+                mInfo.state = mBaseDisplayInfo.state;
             } else {
                 mInfo.copyFrom(mBaseDisplayInfo);
             }
@@ -212,6 +213,7 @@
             mBaseDisplayInfo.logicalDensityDpi = deviceInfo.densityDpi;
             mBaseDisplayInfo.physicalXDpi = deviceInfo.xDpi;
             mBaseDisplayInfo.physicalYDpi = deviceInfo.yDpi;
+            mBaseDisplayInfo.state = deviceInfo.state;
             mBaseDisplayInfo.smallestNominalAppWidth = deviceInfo.width;
             mBaseDisplayInfo.smallestNominalAppHeight = deviceInfo.height;
             mBaseDisplayInfo.largestNominalAppWidth = deviceInfo.width;
diff --git a/services/java/com/android/server/display/OverlayDisplayAdapter.java b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
similarity index 94%
rename from services/java/com/android/server/display/OverlayDisplayAdapter.java
rename to services/core/java/com/android/server/display/OverlayDisplayAdapter.java
index 007acf7..bfd8372c 100644
--- a/services/java/com/android/server/display/OverlayDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
@@ -194,12 +194,14 @@
         private final int mDensityDpi;
         private final boolean mSecure;
 
-        private Surface mSurface;
+        private int mState;
         private SurfaceTexture mSurfaceTexture;
+        private Surface mSurface;
         private DisplayDeviceInfo mInfo;
 
         public OverlayDisplayDevice(IBinder displayToken, String name,
-                int width, int height, float refreshRate, int densityDpi, boolean secure,
+                int width, int height, float refreshRate,
+                int densityDpi, boolean secure, int state,
                 SurfaceTexture surfaceTexture) {
             super(OverlayDisplayAdapter.this, displayToken);
             mName = name;
@@ -208,6 +210,7 @@
             mRefreshRate = refreshRate;
             mDensityDpi = densityDpi;
             mSecure = secure;
+            mState = state;
             mSurfaceTexture = surfaceTexture;
         }
 
@@ -230,6 +233,11 @@
             }
         }
 
+        public void setStateLocked(int state) {
+            mState = state;
+            mInfo = null;
+        }
+
         @Override
         public DisplayDeviceInfo getDisplayDeviceInfoLocked() {
             if (mInfo == null) {
@@ -247,6 +255,7 @@
                 }
                 mInfo.type = Display.TYPE_OVERLAY;
                 mInfo.touch = DisplayDeviceInfo.TOUCH_NONE;
+                mInfo.state = mState;
             }
             return mInfo;
         }
@@ -288,11 +297,12 @@
 
         // Called on the UI thread.
         @Override
-        public void onWindowCreated(SurfaceTexture surfaceTexture, float refreshRate) {
+        public void onWindowCreated(SurfaceTexture surfaceTexture, float refreshRate, int state) {
             synchronized (getSyncRoot()) {
                 IBinder displayToken = SurfaceControl.createDisplay(mName, mSecure);
                 mDevice = new OverlayDisplayDevice(displayToken, mName,
-                        mWidth, mHeight, refreshRate, mDensityDpi, mSecure, surfaceTexture);
+                        mWidth, mHeight, refreshRate, mDensityDpi, mSecure,
+                        state, surfaceTexture);
 
                 sendDisplayDeviceEventLocked(mDevice, DISPLAY_DEVICE_EVENT_ADDED);
             }
@@ -309,6 +319,17 @@
             }
         }
 
+        // Called on the UI thread.
+        @Override
+        public void onStateChanged(int state) {
+            synchronized (getSyncRoot()) {
+                if (mDevice != null) {
+                    mDevice.setStateLocked(state);
+                    sendDisplayDeviceEventLocked(mDevice, DISPLAY_DEVICE_EVENT_CHANGED);
+                }
+            }
+        }
+
         public void dumpLocked(PrintWriter pw) {
             pw.println("  " + mName + ":");
             pw.println("    mWidth=" + mWidth);
diff --git a/services/java/com/android/server/display/OverlayDisplayWindow.java b/services/core/java/com/android/server/display/OverlayDisplayWindow.java
similarity index 97%
rename from services/java/com/android/server/display/OverlayDisplayWindow.java
rename to services/core/java/com/android/server/display/OverlayDisplayWindow.java
index f1dd60a..06891f3 100644
--- a/services/java/com/android/server/display/OverlayDisplayWindow.java
+++ b/services/core/java/com/android/server/display/OverlayDisplayWindow.java
@@ -282,6 +282,7 @@
             if (displayId == mDefaultDisplay.getDisplayId()) {
                 if (updateDefaultDisplayInfo()) {
                     relayout();
+                    mListener.onStateChanged(mDefaultDisplayInfo.state);
                 } else {
                     dismiss();
                 }
@@ -301,7 +302,8 @@
         @Override
         public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture,
                 int width, int height) {
-            mListener.onWindowCreated(surfaceTexture, mDefaultDisplayInfo.refreshRate);
+            mListener.onWindowCreated(surfaceTexture, mDefaultDisplayInfo.refreshRate,
+                    mDefaultDisplayInfo.state);
         }
 
         @Override
@@ -370,7 +372,9 @@
      * Watches for significant changes in the overlay display window lifecycle.
      */
     public interface Listener {
-        public void onWindowCreated(SurfaceTexture surfaceTexture, float refreshRate);
+        public void onWindowCreated(SurfaceTexture surfaceTexture,
+                float refreshRate, int state);
         public void onWindowDestroyed();
+        public void onStateChanged(int state);
     }
 }
\ No newline at end of file
diff --git a/services/java/com/android/server/display/PersistentDataStore.java b/services/core/java/com/android/server/display/PersistentDataStore.java
similarity index 100%
rename from services/java/com/android/server/display/PersistentDataStore.java
rename to services/core/java/com/android/server/display/PersistentDataStore.java
diff --git a/services/java/com/android/server/power/RampAnimator.java b/services/core/java/com/android/server/display/RampAnimator.java
similarity index 98%
rename from services/java/com/android/server/power/RampAnimator.java
rename to services/core/java/com/android/server/display/RampAnimator.java
index 4a4f080..6688d6a 100644
--- a/services/java/com/android/server/power/RampAnimator.java
+++ b/services/core/java/com/android/server/display/RampAnimator.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.power;
+package com.android.server.display;
 
 import android.animation.ValueAnimator;
 import android.util.IntProperty;
diff --git a/services/java/com/android/server/display/VirtualDisplayAdapter.java b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
similarity index 86%
rename from services/java/com/android/server/display/VirtualDisplayAdapter.java
rename to services/core/java/com/android/server/display/VirtualDisplayAdapter.java
index 46d473c..a165f26 100644
--- a/services/java/com/android/server/display/VirtualDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
@@ -69,6 +69,13 @@
         return device;
     }
 
+    public void setVirtualDisplaySurfaceLocked(IBinder appToken, Surface surface) {
+        VirtualDisplayDevice device = mVirtualDisplayDevices.get(appToken);
+        if (device != null) {
+            device.setSurfaceLocked(surface);
+        }
+    }
+
     public DisplayDevice releaseVirtualDisplayLocked(IBinder appToken) {
         VirtualDisplayDevice device = mVirtualDisplayDevices.remove(appToken);
         if (device != null) {
@@ -144,6 +151,17 @@
             }
         }
 
+        public void setSurfaceLocked(Surface surface) {
+            if (mSurface != surface) {
+                if ((mSurface != null) != (surface != null)) {
+                    sendDisplayDeviceEventLocked(this, DISPLAY_DEVICE_EVENT_CHANGED);
+                }
+                sendTraversalRequestLocked();
+                mSurface = surface;
+                mInfo = null;
+            }
+        }
+
         @Override
         public DisplayDeviceInfo getDisplayDeviceInfoLocked() {
             if (mInfo == null) {
@@ -157,8 +175,11 @@
                 mInfo.yDpi = mDensityDpi;
                 mInfo.flags = 0;
                 if ((mFlags & DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC) == 0) {
-                    mInfo.flags |= DisplayDeviceInfo.FLAG_PRIVATE |
-                            DisplayDeviceInfo.FLAG_NEVER_BLANK;
+                    mInfo.flags |= DisplayDeviceInfo.FLAG_PRIVATE
+                            | DisplayDeviceInfo.FLAG_NEVER_BLANK
+                            | DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY;
+                } else if ((mFlags & DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY) != 0) {
+                    mInfo.flags |= DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY;
                 }
                 if ((mFlags & DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE) != 0) {
                     mInfo.flags |= DisplayDeviceInfo.FLAG_SECURE;
@@ -168,6 +189,7 @@
                 }
                 mInfo.type = Display.TYPE_VIRTUAL;
                 mInfo.touch = DisplayDeviceInfo.TOUCH_NONE;
+                mInfo.state = mSurface != null ? Display.STATE_ON : Display.STATE_OFF;
                 mInfo.ownerUid = mOwnerUid;
                 mInfo.ownerPackageName = mOwnerPackageName;
             }
diff --git a/services/java/com/android/server/display/WifiDisplayAdapter.java b/services/core/java/com/android/server/display/WifiDisplayAdapter.java
similarity index 100%
rename from services/java/com/android/server/display/WifiDisplayAdapter.java
rename to services/core/java/com/android/server/display/WifiDisplayAdapter.java
diff --git a/services/java/com/android/server/display/WifiDisplayController.java b/services/core/java/com/android/server/display/WifiDisplayController.java
similarity index 100%
rename from services/java/com/android/server/display/WifiDisplayController.java
rename to services/core/java/com/android/server/display/WifiDisplayController.java
diff --git a/services/java/com/android/server/dreams/DreamController.java b/services/core/java/com/android/server/dreams/DreamController.java
similarity index 91%
rename from services/java/com/android/server/dreams/DreamController.java
rename to services/core/java/com/android/server/dreams/DreamController.java
index 85ef33e..649b5c9 100644
--- a/services/java/com/android/server/dreams/DreamController.java
+++ b/services/core/java/com/android/server/dreams/DreamController.java
@@ -85,6 +85,7 @@
             pw.println("    mToken=" + mCurrentDream.mToken);
             pw.println("    mName=" + mCurrentDream.mName);
             pw.println("    mIsTest=" + mCurrentDream.mIsTest);
+            pw.println("    mCanDoze=" + mCurrentDream.mCanDoze);
             pw.println("    mUserId=" + mCurrentDream.mUserId);
             pw.println("    mBound=" + mCurrentDream.mBound);
             pw.println("    mService=" + mCurrentDream.mService);
@@ -94,15 +95,18 @@
         }
     }
 
-    public void startDream(Binder token, ComponentName name, boolean isTest, int userId) {
+    public void startDream(Binder token, ComponentName name,
+            boolean isTest, boolean canDoze, int userId) {
         stopDream();
 
         // Close the notification shade. Don't need to send to all, but better to be explicit.
         mContext.sendBroadcastAsUser(mCloseNotificationShadeIntent, UserHandle.ALL);
 
-        Slog.i(TAG, "Starting dream: name=" + name + ", isTest=" + isTest + ", userId=" + userId);
+        Slog.i(TAG, "Starting dream: name=" + name
+                + ", isTest=" + isTest + ", canDoze=" + canDoze
+                + ", userId=" + userId);
 
-        mCurrentDream = new DreamRecord(token, name, isTest, userId);
+        mCurrentDream = new DreamRecord(token, name, isTest, canDoze, userId);
 
         try {
             mIWindowManager.addWindowToken(token, WindowManager.LayoutParams.TYPE_DREAM);
@@ -140,7 +144,8 @@
         final DreamRecord oldDream = mCurrentDream;
         mCurrentDream = null;
         Slog.i(TAG, "Stopping dream: name=" + oldDream.mName
-                + ", isTest=" + oldDream.mIsTest + ", userId=" + oldDream.mUserId);
+                + ", isTest=" + oldDream.mIsTest + ", canDoze=" + oldDream.mCanDoze
+                + ", userId=" + oldDream.mUserId);
 
         mHandler.removeCallbacks(mStopUnconnectedDreamRunnable);
 
@@ -187,7 +192,7 @@
     private void attach(IDreamService service) {
         try {
             service.asBinder().linkToDeath(mCurrentDream, 0);
-            service.attach(mCurrentDream.mToken);
+            service.attach(mCurrentDream.mToken, mCurrentDream.mCanDoze);
         } catch (RemoteException ex) {
             Slog.e(TAG, "The dream service died unexpectedly.", ex);
             stopDream();
@@ -213,6 +218,7 @@
         public final Binder mToken;
         public final ComponentName mName;
         public final boolean mIsTest;
+        public final boolean mCanDoze;
         public final int mUserId;
 
         public boolean mBound;
@@ -221,10 +227,11 @@
         public boolean mSentStartBroadcast;
 
         public DreamRecord(Binder token, ComponentName name,
-                boolean isTest, int userId) {
+                boolean isTest, boolean canDoze, int userId) {
             mToken = token;
             mName = name;
             mIsTest = isTest;
+            mCanDoze = canDoze;
             mUserId  = userId;
         }
 
diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java
new file mode 100644
index 0000000..8968da3
--- /dev/null
+++ b/services/core/java/com/android/server/dreams/DreamManagerService.java
@@ -0,0 +1,656 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.dreams;
+
+import com.android.internal.util.DumpUtils;
+import com.android.server.FgThread;
+import com.android.server.SystemService;
+
+import android.Manifest;
+import android.app.ActivityManager;
+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.PackageManager.NameNotFoundException;
+import android.os.Binder;
+import android.os.Build;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.PowerManager;
+import android.os.SystemClock;
+import android.os.SystemProperties;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.service.dreams.DreamManagerInternal;
+import android.service.dreams.DreamService;
+import android.service.dreams.IDozeHardware;
+import android.service.dreams.IDreamManager;
+import android.text.TextUtils;
+import android.util.Slog;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+import libcore.util.Objects;
+
+/**
+ * Service api for managing dreams.
+ *
+ * @hide
+ */
+public final class DreamManagerService extends SystemService {
+    private static final boolean DEBUG = false;
+    private static final String TAG = "DreamManagerService";
+
+    private final Object mLock = new Object();
+
+    private final Context mContext;
+    private final DreamHandler mHandler;
+    private final DreamController mController;
+    private final PowerManager mPowerManager;
+    private final PowerManager.WakeLock mDozeWakeLock;
+    private final McuHal mMcuHal; // synchronized on self
+
+    private Binder mCurrentDreamToken;
+    private ComponentName mCurrentDreamName;
+    private int mCurrentDreamUserId;
+    private boolean mCurrentDreamIsTest;
+    private boolean mCurrentDreamCanDoze;
+    private boolean mCurrentDreamIsDozing;
+    private DozeHardwareWrapper mCurrentDreamDozeHardware;
+
+    public DreamManagerService(Context context) {
+        super(context);
+        mContext = context;
+        mHandler = new DreamHandler(FgThread.get().getLooper());
+        mController = new DreamController(context, mHandler, mControllerListener);
+
+        mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
+        mDozeWakeLock = mPowerManager.newWakeLock(PowerManager.DOZE_WAKE_LOCK, TAG);
+
+        mMcuHal = McuHal.open();
+        if (mMcuHal != null) {
+            mMcuHal.reset();
+        }
+    }
+
+    @Override
+    public void onStart() {
+        publishBinderService(DreamService.DREAM_SERVICE, new BinderService());
+        publishLocalService(DreamManagerInternal.class, new LocalService());
+    }
+
+    @Override
+    public void onBootPhase(int phase) {
+        if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
+            mContext.registerReceiver(new BroadcastReceiver() {
+                @Override
+                public void onReceive(Context context, Intent intent) {
+                    synchronized (mLock) {
+                        stopDreamLocked();
+                    }
+                }
+            }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mHandler);
+        }
+    }
+
+    private void dumpInternal(PrintWriter pw) {
+        pw.println("DREAM MANAGER (dumpsys dreams)");
+        pw.println();
+
+        pw.println("mMcuHal=" + mMcuHal);
+        pw.println();
+        pw.println("mCurrentDreamToken=" + mCurrentDreamToken);
+        pw.println("mCurrentDreamName=" + mCurrentDreamName);
+        pw.println("mCurrentDreamUserId=" + mCurrentDreamUserId);
+        pw.println("mCurrentDreamIsTest=" + mCurrentDreamIsTest);
+        pw.println("mCurrentDreamCanDoze=" + mCurrentDreamCanDoze);
+        pw.println("mCurrentDreamIsDozing=" + mCurrentDreamIsDozing);
+        pw.println("mCurrentDreamDozeHardware=" + mCurrentDreamDozeHardware);
+        pw.println();
+
+        DumpUtils.dumpAsync(mHandler, new DumpUtils.Dump() {
+            @Override
+            public void dump(PrintWriter pw) {
+                mController.dump(pw);
+            }
+        }, pw, 200);
+    }
+
+    private boolean isDreamingInternal() {
+        synchronized (mLock) {
+            return mCurrentDreamToken != null && !mCurrentDreamIsTest;
+        }
+    }
+
+    private void requestDreamInternal() {
+        // Ask the power manager to nap.  It will eventually call back into
+        // startDream() if/when it is appropriate to start dreaming.
+        // Because napping could cause the screen to turn off immediately if the dream
+        // cannot be started, we keep one eye open and gently poke user activity.
+        long time = SystemClock.uptimeMillis();
+        mPowerManager.userActivity(time, true /*noChangeLights*/);
+        mPowerManager.nap(time);
+    }
+
+    private void requestAwakenInternal() {
+        // Treat an explicit request to awaken as user activity so that the
+        // device doesn't immediately go to sleep if the timeout expired,
+        // for example when being undocked.
+        long time = SystemClock.uptimeMillis();
+        mPowerManager.userActivity(time, false /*noChangeLights*/);
+        stopDreamInternal();
+    }
+
+    private void finishSelfInternal(IBinder token) {
+        if (DEBUG) {
+            Slog.d(TAG, "Dream finished: " + token);
+        }
+
+        // Note that a dream finishing and self-terminating is not
+        // itself considered user activity.  If the dream is ending because
+        // the user interacted with the device then user activity will already
+        // have been poked so the device will stay awake a bit longer.
+        // If the dream is ending on its own for other reasons and no wake
+        // locks are held and the user activity timeout has expired then the
+        // device may simply go to sleep.
+        synchronized (mLock) {
+            if (mCurrentDreamToken == token) {
+                stopDreamLocked();
+            }
+        }
+    }
+
+    private void testDreamInternal(ComponentName dream, int userId) {
+        synchronized (mLock) {
+            startDreamLocked(dream, true /*isTest*/, false /*canDoze*/, userId);
+        }
+    }
+
+    private void startDreamInternal(boolean doze) {
+        final int userId = ActivityManager.getCurrentUser();
+        final ComponentName dream = doze ? getDozeComponent() : chooseDreamForUser(userId);
+        if (dream != null) {
+            synchronized (mLock) {
+                startDreamLocked(dream, false /*isTest*/, doze, userId);
+            }
+        }
+    }
+
+    private void stopDreamInternal() {
+        synchronized (mLock) {
+            stopDreamLocked();
+        }
+    }
+
+    private void startDozingInternal(IBinder token) {
+        if (DEBUG) {
+            Slog.d(TAG, "Dream requested to start dozing: " + token);
+        }
+
+        synchronized (mLock) {
+            if (mCurrentDreamToken == token && mCurrentDreamCanDoze
+                    && !mCurrentDreamIsDozing) {
+                mCurrentDreamIsDozing = true;
+                mDozeWakeLock.acquire();
+            }
+        }
+    }
+
+    private void stopDozingInternal(IBinder token) {
+        if (DEBUG) {
+            Slog.d(TAG, "Dream requested to stop dozing: " + token);
+        }
+
+        synchronized (mLock) {
+            if (mCurrentDreamToken == token && mCurrentDreamIsDozing) {
+                mCurrentDreamIsDozing = false;
+                mDozeWakeLock.release();
+            }
+        }
+    }
+
+    private IDozeHardware getDozeHardwareInternal(IBinder token) {
+        synchronized (mLock) {
+            if (mCurrentDreamToken == token && mCurrentDreamCanDoze
+                    && mCurrentDreamDozeHardware == null && mMcuHal != null) {
+                mCurrentDreamDozeHardware = new DozeHardwareWrapper();
+                return mCurrentDreamDozeHardware;
+            }
+            return null;
+        }
+    }
+
+    private ComponentName chooseDreamForUser(int userId) {
+        ComponentName[] dreams = getDreamComponentsForUser(userId);
+        return dreams != null && dreams.length != 0 ? dreams[0] : null;
+    }
+
+    private ComponentName[] getDreamComponentsForUser(int userId) {
+        String names = Settings.Secure.getStringForUser(mContext.getContentResolver(),
+                Settings.Secure.SCREENSAVER_COMPONENTS,
+                userId);
+        ComponentName[] components = componentsFromString(names);
+
+        // first, ensure components point to valid services
+        List<ComponentName> validComponents = new ArrayList<ComponentName>();
+        if (components != null) {
+            for (ComponentName component : components) {
+                if (serviceExists(component)) {
+                    validComponents.add(component);
+                } else {
+                    Slog.w(TAG, "Dream " + component + " does not exist");
+                }
+            }
+        }
+
+        // fallback to the default dream component if necessary
+        if (validComponents.isEmpty()) {
+            ComponentName defaultDream = getDefaultDreamComponentForUser(userId);
+            if (defaultDream != null) {
+                Slog.w(TAG, "Falling back to default dream " + defaultDream);
+                validComponents.add(defaultDream);
+            }
+        }
+        return validComponents.toArray(new ComponentName[validComponents.size()]);
+    }
+
+    private void setDreamComponentsForUser(int userId, ComponentName[] componentNames) {
+        Settings.Secure.putStringForUser(mContext.getContentResolver(),
+                Settings.Secure.SCREENSAVER_COMPONENTS,
+                componentsToString(componentNames),
+                userId);
+    }
+
+    private ComponentName getDefaultDreamComponentForUser(int userId) {
+        String name = Settings.Secure.getStringForUser(mContext.getContentResolver(),
+                Settings.Secure.SCREENSAVER_DEFAULT_COMPONENT,
+                userId);
+        return name == null ? null : ComponentName.unflattenFromString(name);
+    }
+
+    private ComponentName getDozeComponent() {
+        // Read the component from a system property to facilitate debugging.
+        // Note that for production devices, the dream should actually be declared in
+        // a config.xml resource.
+        String name = Build.IS_DEBUGGABLE ? SystemProperties.get("debug.doze.component") : null;
+        if (TextUtils.isEmpty(name)) {
+            // Read the component from a config.xml resource.
+            // The value should be specified in a resource overlay for the product.
+            name = mContext.getResources().getString(
+                    com.android.internal.R.string.config_dozeComponent);
+        }
+        return TextUtils.isEmpty(name) ? null : ComponentName.unflattenFromString(name);
+    }
+
+    private boolean serviceExists(ComponentName name) {
+        try {
+            return name != null && mContext.getPackageManager().getServiceInfo(name, 0) != null;
+        } catch (NameNotFoundException e) {
+            return false;
+        }
+    }
+
+    private void startDreamLocked(final ComponentName name,
+            final boolean isTest, final boolean canDoze, final int userId) {
+        if (Objects.equal(mCurrentDreamName, name)
+                && mCurrentDreamIsTest == isTest
+                && mCurrentDreamCanDoze == canDoze
+                && mCurrentDreamUserId == userId) {
+            return;
+        }
+
+        stopDreamLocked();
+
+        if (DEBUG) Slog.i(TAG, "Entering dreamland.");
+
+        final Binder newToken = new Binder();
+        mCurrentDreamToken = newToken;
+        mCurrentDreamName = name;
+        mCurrentDreamIsTest = isTest;
+        mCurrentDreamCanDoze = canDoze;
+        mCurrentDreamUserId = userId;
+
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                mController.startDream(newToken, name, isTest, canDoze, userId);
+            }
+        });
+    }
+
+    private void stopDreamLocked() {
+        if (mCurrentDreamToken != null) {
+            if (DEBUG) Slog.i(TAG, "Leaving dreamland.");
+
+            cleanupDreamLocked();
+
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    mController.stopDream();
+                }
+            });
+        }
+    }
+
+    private void cleanupDreamLocked() {
+        mCurrentDreamToken = null;
+        mCurrentDreamName = null;
+        mCurrentDreamIsTest = false;
+        mCurrentDreamCanDoze = false;
+        mCurrentDreamUserId = 0;
+        if (mCurrentDreamIsDozing) {
+            mCurrentDreamIsDozing = false;
+            mDozeWakeLock.release();
+        }
+        if (mCurrentDreamDozeHardware != null) {
+            mCurrentDreamDozeHardware.release();
+            mCurrentDreamDozeHardware = null;
+        }
+    }
+
+    private void checkPermission(String permission) {
+        if (mContext.checkCallingOrSelfPermission(permission)
+                != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException("Access denied to process: " + Binder.getCallingPid()
+                    + ", must have permission " + permission);
+        }
+    }
+
+    private static String componentsToString(ComponentName[] componentNames) {
+        StringBuilder names = new StringBuilder();
+        if (componentNames != null) {
+            for (ComponentName componentName : componentNames) {
+                if (names.length() > 0) {
+                    names.append(',');
+                }
+                names.append(componentName.flattenToString());
+            }
+        }
+        return names.toString();
+    }
+
+    private static ComponentName[] componentsFromString(String names) {
+        if (names == null) {
+            return null;
+        }
+        String[] namesArray = names.split(",");
+        ComponentName[] componentNames = new ComponentName[namesArray.length];
+        for (int i = 0; i < namesArray.length; i++) {
+            componentNames[i] = ComponentName.unflattenFromString(namesArray[i]);
+        }
+        return componentNames;
+    }
+
+    private final DreamController.Listener mControllerListener = new DreamController.Listener() {
+        @Override
+        public void onDreamStopped(Binder token) {
+            synchronized (mLock) {
+                if (mCurrentDreamToken == token) {
+                    cleanupDreamLocked();
+                }
+            }
+        }
+    };
+
+    /**
+     * Handler for asynchronous operations performed by the dream manager.
+     * Ensures operations to {@link DreamController} are single-threaded.
+     */
+    private final class DreamHandler extends Handler {
+        public DreamHandler(Looper looper) {
+            super(looper, null, true /*async*/);
+        }
+    }
+
+    private final class BinderService extends IDreamManager.Stub {
+        @Override // Binder call
+        protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+            if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP)
+                    != PackageManager.PERMISSION_GRANTED) {
+                pw.println("Permission Denial: can't dump DreamManager from from pid="
+                        + Binder.getCallingPid()
+                        + ", uid=" + Binder.getCallingUid());
+                return;
+            }
+
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                dumpInternal(pw);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
+        @Override // Binder call
+        public ComponentName[] getDreamComponents() {
+            checkPermission(android.Manifest.permission.READ_DREAM_STATE);
+
+            final int userId = UserHandle.getCallingUserId();
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                return getDreamComponentsForUser(userId);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
+        @Override // Binder call
+        public void setDreamComponents(ComponentName[] componentNames) {
+            checkPermission(android.Manifest.permission.WRITE_DREAM_STATE);
+
+            final int userId = UserHandle.getCallingUserId();
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                setDreamComponentsForUser(userId, componentNames);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
+        @Override // Binder call
+        public ComponentName getDefaultDreamComponent() {
+            checkPermission(android.Manifest.permission.READ_DREAM_STATE);
+
+            final int userId = UserHandle.getCallingUserId();
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                return getDefaultDreamComponentForUser(userId);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
+        @Override // Binder call
+        public boolean isDreaming() {
+            checkPermission(android.Manifest.permission.READ_DREAM_STATE);
+
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                return isDreamingInternal();
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
+        @Override // Binder call
+        public void dream() {
+            checkPermission(android.Manifest.permission.WRITE_DREAM_STATE);
+
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                requestDreamInternal();
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
+        @Override // Binder call
+        public void testDream(ComponentName dream) {
+            if (dream == null) {
+                throw new IllegalArgumentException("dream must not be null");
+            }
+            checkPermission(android.Manifest.permission.WRITE_DREAM_STATE);
+
+            final int callingUserId = UserHandle.getCallingUserId();
+            final int currentUserId = ActivityManager.getCurrentUser();
+            if (callingUserId != currentUserId) {
+                // This check is inherently prone to races but at least it's something.
+                Slog.w(TAG, "Aborted attempt to start a test dream while a different "
+                        + " user is active: callingUserId=" + callingUserId
+                        + ", currentUserId=" + currentUserId);
+                return;
+            }
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                testDreamInternal(dream, callingUserId);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
+        @Override // Binder call
+        public void awaken() {
+            checkPermission(android.Manifest.permission.WRITE_DREAM_STATE);
+
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                requestAwakenInternal();
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
+        @Override // Binder call
+        public void finishSelf(IBinder token) {
+            // Requires no permission, called by Dream from an arbitrary process.
+            if (token == null) {
+                throw new IllegalArgumentException("token must not be null");
+            }
+
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                finishSelfInternal(token);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
+        @Override // Binder call
+        public void startDozing(IBinder token) {
+            // Requires no permission, called by Dream from an arbitrary process.
+            if (token == null) {
+                throw new IllegalArgumentException("token must not be null");
+            }
+
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                startDozingInternal(token);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
+        @Override // Binder call
+        public void stopDozing(IBinder token) {
+            // Requires no permission, called by Dream from an arbitrary process.
+            if (token == null) {
+                throw new IllegalArgumentException("token must not be null");
+            }
+
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                stopDozingInternal(token);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
+        @Override // Binder call
+        public IDozeHardware getDozeHardware(IBinder token) {
+            // Requires no permission, called by Dream from an arbitrary process.
+            if (token == null) {
+                throw new IllegalArgumentException("token must not be null");
+            }
+
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                return getDozeHardwareInternal(token);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+    }
+
+    private final class LocalService extends DreamManagerInternal {
+        @Override
+        public void startDream(boolean doze) {
+            startDreamInternal(doze);
+        }
+
+        @Override
+        public void stopDream() {
+            stopDreamInternal();
+        }
+
+        @Override
+        public boolean isDreaming() {
+            return isDreamingInternal();
+        }
+    }
+
+    private final class DozeHardwareWrapper extends IDozeHardware.Stub {
+        private boolean mReleased;
+
+        public void release() {
+            synchronized (mMcuHal) {
+                if (!mReleased) {
+                    mReleased = true;
+                    mMcuHal.reset();
+                }
+            }
+        }
+
+        @Override // Binder call
+        public byte[] sendMessage(String msg, byte[] arg) {
+            if (msg == null) {
+                throw new IllegalArgumentException("msg must not be null");
+            }
+
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                synchronized (mMcuHal) {
+                    if (mReleased) {
+                        Slog.w(TAG, "Ignoring message to MCU HAL because the dream "
+                                + "has already ended: " + msg);
+                        return null;
+                    }
+                    return mMcuHal.sendMessage(msg, arg);
+                }
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/dreams/McuHal.java b/services/core/java/com/android/server/dreams/McuHal.java
new file mode 100644
index 0000000..1dc79c7
--- /dev/null
+++ b/services/core/java/com/android/server/dreams/McuHal.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.dreams;
+
+import android.service.dreams.DozeHardware;
+
+/**
+ * Provides access to the low-level microcontroller hardware abstraction layer.
+ */
+final class McuHal {
+    private final long mPtr;
+
+    private static native long nativeOpen();
+    private static native byte[] nativeSendMessage(long ptr, String msg, byte[] arg);
+
+    private McuHal(long ptr) {
+        mPtr = ptr;
+    }
+
+    public static McuHal open() {
+        long ptr = nativeOpen();
+        return ptr != 0 ? new McuHal(ptr) : null;
+    }
+
+    public void reset() {
+        sendMessage(DozeHardware.MSG_ENABLE_MCU, DozeHardware.VALUE_OFF);
+    }
+
+    public byte[] sendMessage(String msg, byte[] arg) {
+        return nativeSendMessage(mPtr, msg, arg);
+    }
+}
diff --git a/services/java/com/android/server/firewall/AndFilter.java b/services/core/java/com/android/server/firewall/AndFilter.java
similarity index 100%
rename from services/java/com/android/server/firewall/AndFilter.java
rename to services/core/java/com/android/server/firewall/AndFilter.java
diff --git a/services/java/com/android/server/firewall/CategoryFilter.java b/services/core/java/com/android/server/firewall/CategoryFilter.java
similarity index 100%
rename from services/java/com/android/server/firewall/CategoryFilter.java
rename to services/core/java/com/android/server/firewall/CategoryFilter.java
diff --git a/services/java/com/android/server/firewall/Filter.java b/services/core/java/com/android/server/firewall/Filter.java
similarity index 100%
rename from services/java/com/android/server/firewall/Filter.java
rename to services/core/java/com/android/server/firewall/Filter.java
diff --git a/services/java/com/android/server/firewall/FilterFactory.java b/services/core/java/com/android/server/firewall/FilterFactory.java
similarity index 100%
rename from services/java/com/android/server/firewall/FilterFactory.java
rename to services/core/java/com/android/server/firewall/FilterFactory.java
diff --git a/services/java/com/android/server/firewall/FilterList.java b/services/core/java/com/android/server/firewall/FilterList.java
similarity index 100%
rename from services/java/com/android/server/firewall/FilterList.java
rename to services/core/java/com/android/server/firewall/FilterList.java
diff --git a/services/java/com/android/server/firewall/IntentFirewall.java b/services/core/java/com/android/server/firewall/IntentFirewall.java
similarity index 98%
rename from services/java/com/android/server/firewall/IntentFirewall.java
rename to services/core/java/com/android/server/firewall/IntentFirewall.java
index 6df1dbd..eb7a383 100644
--- a/services/java/com/android/server/firewall/IntentFirewall.java
+++ b/services/core/java/com/android/server/firewall/IntentFirewall.java
@@ -26,6 +26,7 @@
 import android.os.Environment;
 import android.os.FileObserver;
 import android.os.Handler;
+import android.os.Looper;
 import android.os.Message;
 import android.os.RemoteException;
 import android.util.ArrayMap;
@@ -106,8 +107,9 @@
         }
     }
 
-    public IntentFirewall(AMSInterface ams) {
+    public IntentFirewall(AMSInterface ams, Handler handler) {
         mAms = ams;
+        mHandler = new FirewallHandler(handler.getLooper());
         File rulesDir = getRulesDir();
         rulesDir.mkdirs();
 
@@ -533,7 +535,13 @@
                 new ArrayMap<ComponentName, Rule[]>(0);
     }
 
-    final Handler mHandler = new Handler() {
+    final FirewallHandler mHandler;
+
+    private final class FirewallHandler extends Handler {
+        public FirewallHandler(Looper looper) {
+            super(looper, null, true);
+        }
+
         @Override
         public void handleMessage(Message msg) {
             readRulesDir(getRulesDir());
diff --git a/services/java/com/android/server/firewall/NotFilter.java b/services/core/java/com/android/server/firewall/NotFilter.java
similarity index 100%
rename from services/java/com/android/server/firewall/NotFilter.java
rename to services/core/java/com/android/server/firewall/NotFilter.java
diff --git a/services/java/com/android/server/firewall/OrFilter.java b/services/core/java/com/android/server/firewall/OrFilter.java
similarity index 100%
rename from services/java/com/android/server/firewall/OrFilter.java
rename to services/core/java/com/android/server/firewall/OrFilter.java
diff --git a/services/java/com/android/server/firewall/PortFilter.java b/services/core/java/com/android/server/firewall/PortFilter.java
similarity index 100%
rename from services/java/com/android/server/firewall/PortFilter.java
rename to services/core/java/com/android/server/firewall/PortFilter.java
diff --git a/services/java/com/android/server/firewall/SenderFilter.java b/services/core/java/com/android/server/firewall/SenderFilter.java
similarity index 100%
rename from services/java/com/android/server/firewall/SenderFilter.java
rename to services/core/java/com/android/server/firewall/SenderFilter.java
diff --git a/services/java/com/android/server/firewall/SenderPermissionFilter.java b/services/core/java/com/android/server/firewall/SenderPermissionFilter.java
similarity index 100%
rename from services/java/com/android/server/firewall/SenderPermissionFilter.java
rename to services/core/java/com/android/server/firewall/SenderPermissionFilter.java
diff --git a/services/java/com/android/server/firewall/StringFilter.java b/services/core/java/com/android/server/firewall/StringFilter.java
similarity index 100%
rename from services/java/com/android/server/firewall/StringFilter.java
rename to services/core/java/com/android/server/firewall/StringFilter.java
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecDevice.java
new file mode 100644
index 0000000..baae1d9
--- /dev/null
+++ b/services/core/java/com/android/server/hdmi/HdmiCecDevice.java
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.hdmi;
+
+import android.hardware.hdmi.HdmiCec;
+import android.hardware.hdmi.HdmiCecMessage;
+import android.hardware.hdmi.IHdmiCecListener;
+import android.os.Binder;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * HdmiCecDevice class represents a CEC logical device characterized
+ * by its device type. It is a superclass of those serving concrete device type.
+ * Currently we're interested in playback(one of sources), display(sink) device type
+ * only. The support for the other types like recorder, audio system will come later.
+ *
+ * <p>A physical device can contain the functions of
+ * more than one logical device, in which case it should create
+ * as many logical devices as necessary.
+ *
+ * <p>Note that if a physical device has multiple instances of a particular
+ * functionality, it should advertize only one instance. For instance, if
+ * a device has multiple tuners, it should only expose one for control
+ * via CEC. In this case, it is up to the device itself to manage multiple tuners.
+ *
+ * <p>The version of HDMI-CEC protocol supported in this class is 1.3a.
+ *
+ * <p>Declared as package-private, accessed by HdmiCecService only.
+ */
+abstract class HdmiCecDevice {
+    private static final String TAG = "HdmiCecDevice";
+
+    private final int mType;
+
+    // List of listeners to the message/event coming to the device.
+    private final List<IHdmiCecListener> mListeners = new ArrayList<IHdmiCecListener>();
+    private final Binder mBinder = new Binder();
+    private final HdmiCecService mService;
+
+    private boolean mIsActiveSource;
+
+    /**
+     * Factory method that creates HdmiCecDevice instance to the device type.
+     */
+    public static HdmiCecDevice create(HdmiCecService service, int type) {
+        if (type == HdmiCec.DEVICE_PLAYBACK) {
+            return new HdmiCecDevicePlayback(service, type);
+        } else if (type == HdmiCec.DEVICE_TV) {
+            return new HdmiCecDeviceTv(service, type);
+        }
+        return null;
+    }
+
+    /**
+     * Constructor.
+     */
+    public HdmiCecDevice(HdmiCecService service, int type) {
+        mService = service;
+        mType = type;
+        mIsActiveSource = false;
+    }
+
+    /**
+     * Called right after the class is instantiated. This method can be used to
+     * implement any initialization tasks for the instance.
+     */
+    abstract public void initialize();
+
+    /**
+     * Return the binder token that identifies this instance.
+     */
+    public Binder getToken() {
+        return mBinder;
+    }
+
+    /**
+     * Return the service instance.
+     */
+    public HdmiCecService getService() {
+        return mService;
+    }
+
+    /**
+     * Return the type of this device.
+     */
+    public int getType() {
+        return mType;
+    }
+
+    /**
+     * Register a listener to be invoked when events occur.
+     *
+     * @param listener the listern that will run
+     */
+    public void addListener(IHdmiCecListener listener) {
+        mListeners.add(listener);
+    }
+
+    /**
+     * Remove the listener that was previously registered.
+     *
+     * @param listener IHdmiCecListener instance to be removed
+     */
+    public void removeListener(IHdmiCecListener listener) {
+        mListeners.remove(listener);
+    }
+
+    /**
+     * Indicate if the device has listeners.
+     *
+     * @return true if there are listener instances for this device
+     */
+    public boolean hasListener() {
+        return !mListeners.isEmpty();
+    }
+
+    /**
+     * Handle HDMI-CEC message coming to the device by invoking the registered
+     * listeners.
+     */
+    public void handleMessage(int srcAddress, int dstAddress, int opcode, byte[] params) {
+        if (opcode == HdmiCec.MESSAGE_ACTIVE_SOURCE) {
+            mIsActiveSource = false;
+        }
+
+        if (mListeners.size() == 0) {
+            return;
+        }
+        HdmiCecMessage message = new HdmiCecMessage(srcAddress, dstAddress, opcode, params);
+        for (IHdmiCecListener listener : mListeners) {
+            try {
+                listener.onMessageReceived(message);
+            } catch (RemoteException e) {
+                Log.e(TAG, "listener.onMessageReceived failed.");
+            }
+        }
+    }
+
+    public void handleHotplug(boolean connected) {
+        for (IHdmiCecListener listener : mListeners) {
+            try {
+                listener.onCableStatusChanged(connected);
+            } catch (RemoteException e) {
+                Log.e(TAG, "listener.onCableStatusChanged failed.");
+            }
+        }
+    }
+
+    /**
+     * Return the active status of the device.
+     *
+     * @return true if the device is the active source among the connected
+     *         HDMI-CEC-enabled devices; otherwise false.
+     */
+    public boolean isActiveSource() {
+        return mIsActiveSource;
+    }
+
+    /**
+     * Update the active source state of the device.
+     */
+    public void setIsActiveSource(boolean state) {
+        mIsActiveSource = state;
+    }
+
+    /**
+     * Send &lt;Active Source&gt; command. The default implementation does nothing. Should be
+     * overriden by subclass.
+     */
+    public void sendActiveSource(int physicalAddress) {
+        logWarning("<Active Source> not valid for the device type: " + mType
+                + " address:" + physicalAddress);
+    }
+
+    /**
+     * Send &lt;Inactive Source&gt; command. The default implementation does nothing. Should be
+     * overriden by subclass.
+     */
+    public void sendInactiveSource(int physicalAddress) {
+        logWarning("<Inactive Source> not valid for the device type: " + mType
+                + " address:" + physicalAddress);
+    }
+
+    /**
+     * Send &lt;Image View On&gt; command. The default implementation does nothing. Should be
+     * overriden by subclass.
+     */
+    public void sendImageViewOn() {
+        logWarning("<Image View On> not valid for the device type: " + mType);
+    }
+
+    /**
+     * Send &lt;Text View On&gt; command. The default implementation does nothing. Should be
+     * overriden by subclass.
+     */
+    public void sendTextViewOn() {
+        logWarning("<Text View On> not valid for the device type: " + mType);
+    }
+
+    /**
+     * Check if the connected sink device is in powered-on state. The default implementation
+     * simply returns false. Should be overriden by subclass to report the correct state.
+     */
+    public boolean isSinkDeviceOn() {
+        logWarning("isSinkDeviceOn() not valid for the device type: " + mType);
+        return false;
+    }
+
+    private void logWarning(String msg) {
+        Log.w(TAG, msg);
+    }
+}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecDevicePlayback.java
new file mode 100644
index 0000000..f8cf11d
--- /dev/null
+++ b/services/core/java/com/android/server/hdmi/HdmiCecDevicePlayback.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.hdmi;
+
+import android.hardware.hdmi.HdmiCec;
+
+/**
+ * Class for the logical device of playback type. Devices such as DVD/Blueray player
+ * that support 'playback' feature are classified as playback device. It is common
+ * that they don't have built-in display, therefore need to talk, stream their contents
+ * to TV/display device which is connected through HDMI cable.
+ *
+ * <p>It closely monitors the status of display device (other devices can be of interest
+ * too, but with much less priority), declares itself as 'active source' to have
+ * display show its output, switch the source state as ordered by display that may be
+ * talking to many other devices connected to it. It also receives commands from display
+ * such as remote control signal, standby, status report, playback mode.
+ *
+ * <p>Declared as package-private, accessed by HdmiCecService only.
+ */
+final class HdmiCecDevicePlayback extends HdmiCecDevice {
+    private static final String TAG = "HdmiCecDevicePlayback";
+
+    private int mSinkDevicePowerStatus;
+
+    /**
+     * Constructor.
+     */
+    public HdmiCecDevicePlayback(HdmiCecService service, int type) {
+        super(service, type);
+        mSinkDevicePowerStatus = HdmiCec.POWER_STATUS_UNKNOWN;
+    }
+
+    @Override
+    public void initialize() {
+        // Playback device tries to obtain the power status of TV/display when created,
+        // and maintains it all through its lifecycle. CEC spec says there is
+        // a maximum 1 second response time. Therefore it should be kept in mind
+        // that there can be as much amount of period of time the power status
+        // of the display remains unknown after the query is sent out.
+        queryTvPowerStatus();
+    }
+
+    private void queryTvPowerStatus() {
+        getService().sendMessage(getType(), HdmiCec.ADDR_TV,
+                HdmiCec.MESSAGE_GIVE_DEVICE_POWER_STATUS, HdmiCecService.EMPTY_PARAM);
+    }
+
+    @Override
+    public void handleMessage(int srcAddress, int dstAddress, int opcode, byte[] params) {
+        // Updates power status of display. The cases are:
+        // 1) Response for the queried power status request arrives. Update the status.
+        // 2) Broadcast or direct <Standby> command from TV, which is sent as TV itself is going
+        //    into standby mode too.
+        if (opcode == HdmiCec.MESSAGE_REPORT_POWER_STATUS) {
+            mSinkDevicePowerStatus = params[0];
+        } else if (srcAddress == HdmiCec.ADDR_TV) {
+            if (opcode == HdmiCec.MESSAGE_STANDBY) {
+                mSinkDevicePowerStatus = HdmiCec.POWER_STATUS_STANDBY;
+            }
+        }
+        super.handleMessage(srcAddress, dstAddress, opcode, params);
+    }
+
+    @Override
+    public void handleHotplug(boolean connected) {
+        // If cable get disconnected sink device becomes unreachable. Switch the status
+        // to unknown, and query the status once the cable gets connected back.
+        if (!connected) {
+            mSinkDevicePowerStatus = HdmiCec.POWER_STATUS_UNKNOWN;
+        } else {
+            queryTvPowerStatus();
+        }
+        super.handleHotplug(connected);
+    }
+
+    @Override
+    public boolean isSinkDeviceOn() {
+        return mSinkDevicePowerStatus == HdmiCec.POWER_STATUS_ON;
+    }
+
+    @Override
+    public void sendActiveSource(int physicalAddress) {
+        setIsActiveSource(true);
+        byte[] param = new byte[] {
+                (byte) ((physicalAddress >> 8) & 0xff),
+                (byte) (physicalAddress & 0xff)
+        };
+        getService().sendMessage(getType(), HdmiCec.ADDR_BROADCAST, HdmiCec.MESSAGE_ACTIVE_SOURCE,
+                param);
+    }
+
+    @Override
+    public void sendInactiveSource(int physicalAddress) {
+        setIsActiveSource(false);
+        byte[] param = new byte[] {
+                (byte) ((physicalAddress >> 8) & 0xff),
+                (byte) (physicalAddress & 0xff)
+        };
+        getService().sendMessage(getType(), HdmiCec.ADDR_TV, HdmiCec.MESSAGE_INACTIVE_SOURCE,
+                param);
+    }
+
+    @Override
+    public void sendImageViewOn() {
+        getService().sendMessage(getType(), HdmiCec.ADDR_TV, HdmiCec.MESSAGE_IMAGE_VIEW_ON,
+                HdmiCecService.EMPTY_PARAM);
+    }
+
+    @Override
+    public void sendTextViewOn() {
+        getService().sendMessage(getType(), HdmiCec.ADDR_TV, HdmiCec.MESSAGE_TEXT_VIEW_ON,
+                HdmiCecService.EMPTY_PARAM);
+    }
+}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecDeviceTv.java
new file mode 100644
index 0000000..09ff3ca
--- /dev/null
+++ b/services/core/java/com/android/server/hdmi/HdmiCecDeviceTv.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.hdmi;
+
+/**
+ * Class for logical device of TV type.
+ */
+final class HdmiCecDeviceTv extends HdmiCecDevice {
+    private static final String TAG = "HdmiCecDeviceTv";
+
+    /**
+     * Constructor.
+     */
+    public HdmiCecDeviceTv(HdmiCecService service, int type) {
+        super(service, type);
+    }
+
+    public void initialize() {
+        // TODO: Do the initialization task for TV device here.
+    }
+}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecService.java b/services/core/java/com/android/server/hdmi/HdmiCecService.java
new file mode 100644
index 0000000..0a4c719
--- /dev/null
+++ b/services/core/java/com/android/server/hdmi/HdmiCecService.java
@@ -0,0 +1,388 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.hdmi;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.hardware.hdmi.HdmiCec;
+import android.hardware.hdmi.HdmiCecMessage;
+import android.hardware.hdmi.IHdmiCecListener;
+import android.hardware.hdmi.IHdmiCecService;
+import android.os.Binder;
+import android.os.Build;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.SparseArray;
+
+import com.android.server.SystemService;
+import libcore.util.EmptyArray;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.Locale;
+
+/**
+ * Provides a service for sending and processing HDMI-CEC messages, and providing
+ * the information on HDMI settings in general.
+ */
+public final class HdmiCecService extends SystemService {
+    private static final String TAG = "HdmiCecService";
+
+    // Maintains the allocated logical devices. Device type, not logical address,
+    // is used for key as logical address is likely to change over time while
+    // device type is permanent. Type-address mapping is maintained only at
+    // native level.
+    private final SparseArray<HdmiCecDevice> mLogicalDevices = new SparseArray<HdmiCecDevice>();
+
+    // List of IBinder.DeathRecipient instances to handle dead IHdmiCecListener
+    // objects.
+    private final ArrayList<ListenerRecord> mListenerRecords = new ArrayList<ListenerRecord>();
+
+    // Used to synchronize the access to the service.
+    private final Object mLock = new Object();
+
+    // Stores the pointer to the native implementation of the service that
+    // interacts with HAL.
+    private long mNativePtr;
+
+    private static final String PERMISSION = "android.permission.HDMI_CEC";
+
+    static final byte[] EMPTY_PARAM = EmptyArray.BYTE;
+
+    public HdmiCecService(Context context) {
+        super(context);
+    }
+
+    private static native long nativeInit(HdmiCecService service);
+
+    @Override
+    public void onStart() {
+        mNativePtr = nativeInit(this);
+        if (mNativePtr != 0) {
+            // TODO: Consider using a dedicated, configurable identifier for OSD name, maybe from
+            //       Settings. It should be ASCII only, not a very long one (limited to 15 chars).
+            setOsdNameLocked(Build.MODEL);
+            publishBinderService(Context.HDMI_CEC_SERVICE, new BinderService());
+        }
+    }
+
+    /**
+     * Called by native when an HDMI-CEC message arrived. Invokes the registered
+     * listeners to handle the message.
+     */
+    private void handleMessage(int srcAddress, int dstAddress, int opcode, byte[] params) {
+        // TODO: Messages like <Standby> may not need be passed to listener
+        //       but better be handled in service by turning off the screen
+        //       or putting the device into suspend mode. List up such messages
+        //       and handle them here.
+        synchronized (mLock) {
+            if (dstAddress == HdmiCec.ADDR_BROADCAST) {
+                for (int i = 0; i < mLogicalDevices.size(); ++i) {
+                    mLogicalDevices.valueAt(i).handleMessage(srcAddress, dstAddress, opcode,
+                            params);
+                }
+            } else {
+                int type = HdmiCec.getTypeFromAddress(dstAddress);
+                HdmiCecDevice device = mLogicalDevices.get(type);
+                if (device == null) {
+                    Log.w(TAG, "logical device not found. type: " + type);
+                    return;
+                }
+                device.handleMessage(srcAddress, dstAddress, opcode, params);
+            }
+        }
+    }
+
+    /**
+     * Called by native when internal HDMI hotplug event occurs. Invokes the registered
+     * listeners to handle the event.
+     */
+    private void handleHotplug(boolean connected) {
+        synchronized(mLock) {
+            for (int i = 0; i < mLogicalDevices.size(); ++i) {
+                mLogicalDevices.valueAt(i).handleHotplug(connected);
+            }
+        }
+    }
+
+    /**
+     * Called by native when it needs to know whether we have an active source.
+     * The native part uses the return value to respond to &lt;Request Active
+     * Source &gt;.
+     *
+     * @return type of the device which is active; DEVICE_INACTIVE if there is
+     *        no active logical device in the system.
+     */
+    private int getActiveSource() {
+        synchronized(mLock) {
+            for (int i = 0; i < mLogicalDevices.size(); ++i) {
+                if (mLogicalDevices.valueAt(i).isActiveSource()) {
+                    return mLogicalDevices.keyAt(i);
+                }
+            }
+        }
+        return HdmiCec.DEVICE_INACTIVE;
+    }
+
+    /**
+     * Called by native when a request for the menu language of the device was
+     * received. The native part uses the return value to generate the message
+     * &lt;Set Menu Language&gt; in response. The language should be of
+     * the 3-letter format as defined in ISO/FDIS 639-2. We use system default
+     * locale.
+     */
+    private String getLanguage(int type) {
+        return Locale.getDefault().getISO3Language();
+    }
+
+    private void enforceAccessPermission() {
+        getContext().enforceCallingOrSelfPermission(PERMISSION, "HdmiCecService");
+    }
+
+    private void dumpInternal(PrintWriter pw) {
+        pw.println("HdmiCecService (dumpsys hdmi_cec)");
+        pw.println("");
+        synchronized (mLock) {
+            for (int i = 0; i < mLogicalDevices.size(); ++i) {
+                HdmiCecDevice device = mLogicalDevices.valueAt(i);
+                pw.println("Device: type=" + device.getType() +
+                           ", active=" + device.isActiveSource());
+            }
+        }
+    }
+
+    // Remove logical device of a given type.
+    private void removeLogicalDeviceLocked(int type) {
+        ensureValidType(type);
+        mLogicalDevices.remove(type);
+        nativeRemoveLogicalAddress(mNativePtr, type);
+    }
+
+    private static void ensureValidType(int type) {
+        if (!HdmiCec.isValidType(type)) {
+            throw new IllegalArgumentException("invalid type: " + type);
+        }
+    }
+
+    // Return the logical device identified by the given binder token.
+    private HdmiCecDevice getLogicalDeviceLocked(IBinder b) {
+        for (int i = 0; i < mLogicalDevices.size(); ++i) {
+            HdmiCecDevice device = mLogicalDevices.valueAt(i);
+            if (device.getToken() == b) {
+                return device;
+            }
+        }
+        throw new IllegalArgumentException("Device not found");
+    }
+
+    // package-private. Used by HdmiCecDevice and its subclasses only.
+    void sendMessage(int type, int address, int opcode, byte[] params) {
+        nativeSendMessage(mNativePtr, type, address, opcode, params);
+    }
+
+    private void setOsdNameLocked(String name) {
+        nativeSetOsdName(mNativePtr, name.getBytes(Charset.forName("US-ASCII")));
+    }
+
+    private final class ListenerRecord implements IBinder.DeathRecipient {
+        private final IHdmiCecListener mListener;
+        private final int mType;
+
+        public ListenerRecord(IHdmiCecListener listener, int type) {
+            mListener = listener;
+            mType = type;
+        }
+
+        @Override
+        public void binderDied() {
+            synchronized (mLock) {
+                mListenerRecords.remove(this);
+                HdmiCecDevice device = mLogicalDevices.get(mType);
+                if (device != null) {
+                    device.removeListener(mListener);
+                    if (!device.hasListener()) {
+                        removeLogicalDeviceLocked(mType);
+                    }
+                }
+            }
+        }
+    }
+
+    private final class BinderService extends IHdmiCecService.Stub {
+
+        @Override
+        public IBinder allocateLogicalDevice(int type, IHdmiCecListener listener) {
+            enforceAccessPermission();
+            ensureValidType(type);
+            if (listener == null) {
+                throw new IllegalArgumentException("listener must not be null");
+            }
+            synchronized (mLock) {
+                HdmiCecDevice device = mLogicalDevices.get(type);
+                if (device != null) {
+                    Log.v(TAG, "Logical address already allocated. Adding listener only.");
+                } else {
+                    int address = nativeAllocateLogicalAddress(mNativePtr, type);
+                    if (!HdmiCec.isValidAddress(address)) {
+                        Log.e(TAG, "Logical address was not allocated");
+                        return null;
+                    } else {
+                        device = HdmiCecDevice.create(HdmiCecService.this, type);
+                        if (device == null) {
+                            Log.e(TAG, "Device type not supported yet.");
+                            return null;
+                        }
+                        device.initialize();
+                        mLogicalDevices.put(type, device);
+                    }
+                }
+
+                // Adds the listener and its monitor
+                ListenerRecord record = new ListenerRecord(listener, type);
+                try {
+                    listener.asBinder().linkToDeath(record, 0);
+                } catch (RemoteException e) {
+                    Log.w(TAG, "Listener already died");
+                    if (!device.hasListener()) {
+                         removeLogicalDeviceLocked(type);
+                    }
+                    return null;
+                }
+                mListenerRecords.add(record);
+                device.addListener(listener);
+                return device.getToken();
+            }
+        }
+
+        @Override
+        public void sendActiveSource(IBinder b) {
+            enforceAccessPermission();
+            synchronized (mLock) {
+                HdmiCecDevice device = getLogicalDeviceLocked(b);
+                device.sendActiveSource(nativeGetPhysicalAddress(mNativePtr));
+            }
+        }
+
+        @Override
+        public void sendInactiveSource(IBinder b) {
+            enforceAccessPermission();
+            synchronized (mLock) {
+                HdmiCecDevice device = getLogicalDeviceLocked(b);
+                device.sendInactiveSource(nativeGetPhysicalAddress(mNativePtr));
+            }
+        }
+
+        @Override
+        public void sendImageViewOn(IBinder b) {
+            enforceAccessPermission();
+            synchronized (mLock) {
+                HdmiCecDevice device = getLogicalDeviceLocked(b);
+                device.sendImageViewOn();
+            }
+        }
+
+        @Override
+        public void sendTextViewOn(IBinder b) {
+            enforceAccessPermission();
+            synchronized (mLock) {
+                HdmiCecDevice device = getLogicalDeviceLocked(b);
+                device.sendTextViewOn();
+            }
+        }
+
+        public void sendGiveDevicePowerStatus(IBinder b, int address) {
+            enforceAccessPermission();
+            synchronized (mLock) {
+                HdmiCecDevice device = getLogicalDeviceLocked(b);
+                nativeSendMessage(mNativePtr, device.getType(), address,
+                        HdmiCec.MESSAGE_GIVE_DEVICE_POWER_STATUS, EMPTY_PARAM);
+            }
+        }
+
+        @Override
+        public boolean isTvOn(IBinder b) {
+            enforceAccessPermission();
+            synchronized (mLock) {
+                HdmiCecDevice device = getLogicalDeviceLocked(b);
+                return device.isSinkDeviceOn();
+            }
+        }
+
+        @Override
+        public void removeServiceListener(IBinder b, IHdmiCecListener listener) {
+            enforceAccessPermission();
+            if (listener == null) {
+                throw new IllegalArgumentException("listener must not be null");
+            }
+            synchronized (mLock) {
+                HdmiCecDevice device = getLogicalDeviceLocked(b);
+                for (ListenerRecord record : mListenerRecords) {
+                    if (record.mType == device.getType()
+                            && record.mListener.asBinder() == listener.asBinder()) {
+                        mListenerRecords.remove(record);
+                        device.removeListener(record.mListener);
+                        if (!device.hasListener()) {
+                            removeLogicalDeviceLocked(record.mType);
+                        }
+                        break;
+                    }
+                }
+            }
+        }
+
+        @Override
+        public void sendMessage(IBinder b, HdmiCecMessage message) {
+            enforceAccessPermission();
+            if (message == null) {
+                throw new IllegalArgumentException("message must not be null");
+            }
+            synchronized (mLock) {
+                HdmiCecDevice device = getLogicalDeviceLocked(b);
+                nativeSendMessage(mNativePtr, device.getType(), message.getDestination(),
+                        message.getOpcode(), message.getParams());
+            }
+        }
+
+        @Override
+        protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+            if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+                    != PackageManager.PERMISSION_GRANTED) {
+                pw.println("Permission denial: can't dump HdmiCecService from pid="
+                        + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
+                        + " without permission " + android.Manifest.permission.DUMP);
+                return;
+            }
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                dumpInternal(pw);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+    }
+
+    private static native int nativeAllocateLogicalAddress(long handler, int deviceType);
+    private static native void nativeRemoveLogicalAddress(long handler, int deviceType);
+    private static native void nativeSendMessage(long handler, int deviceType, int destination,
+            int opcode, byte[] params);
+    private static native int nativeGetPhysicalAddress(long handler);
+    private static native void nativeSetOsdName(long handler, byte[] name);
+}
diff --git a/services/java/com/android/server/input/InputApplicationHandle.java b/services/core/java/com/android/server/input/InputApplicationHandle.java
similarity index 100%
rename from services/java/com/android/server/input/InputApplicationHandle.java
rename to services/core/java/com/android/server/input/InputApplicationHandle.java
diff --git a/services/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
similarity index 91%
rename from services/java/com/android/server/input/InputManagerService.java
rename to services/core/java/com/android/server/input/InputManagerService.java
index 9178664..a32f7c1 100644
--- a/services/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -16,11 +16,12 @@
 
 package com.android.server.input;
 
+import android.view.Display;
 import com.android.internal.R;
 import com.android.internal.util.XmlUtils;
+import com.android.server.DisplayThread;
+import com.android.server.LocalServices;
 import com.android.server.Watchdog;
-import com.android.server.display.DisplayManagerService;
-import com.android.server.display.DisplayViewport;
 
 import org.xmlpull.v1.XmlPullParser;
 
@@ -44,9 +45,12 @@
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
 import android.database.ContentObserver;
+import android.hardware.display.DisplayViewport;
 import android.hardware.input.IInputDevicesChangedListener;
 import android.hardware.input.IInputManager;
+import android.hardware.input.InputDeviceIdentifier;
 import android.hardware.input.InputManager;
+import android.hardware.input.InputManagerInternal;
 import android.hardware.input.KeyboardLayout;
 import android.os.Binder;
 import android.os.Bundle;
@@ -94,7 +98,7 @@
  * Wraps the C++ InputManager and provides its callbacks.
  */
 public class InputManagerService extends IInputManager.Stub
-        implements Watchdog.Monitor, DisplayManagerService.InputManagerFuncs {
+        implements Watchdog.Monitor {
     static final String TAG = "InputManager";
     static final boolean DEBUG = false;
 
@@ -167,7 +171,7 @@
             InputWindowHandle inputWindowHandle, boolean monitor);
     private static native void nativeUnregisterInputChannel(long ptr, InputChannel inputChannel);
     private static native void nativeSetInputFilterEnabled(long ptr, boolean enable);
-    private static native int nativeInjectInputEvent(long ptr, InputEvent event,
+    private static native int nativeInjectInputEvent(long ptr, InputEvent event, int displayId,
             int injectorPid, int injectorUid, int syncMode, int timeoutMillis,
             int policyFlags);
     private static native void nativeSetInputWindows(long ptr, InputWindowHandle[] windowHandles);
@@ -179,6 +183,7 @@
             InputChannel fromChannel, InputChannel toChannel);
     private static native void nativeSetPointerSpeed(long ptr, int speed);
     private static native void nativeSetShowTouches(long ptr, boolean enabled);
+    private static native void nativeSetInteractive(long ptr, boolean interactive);
     private static native void nativeVibrate(long ptr, int deviceId, long[] pattern,
             int repeat, int token);
     private static native void nativeCancelVibrate(long ptr, int deviceId, int token);
@@ -241,15 +246,17 @@
     /** Whether to use the dev/input/event or uevent subsystem for the audio jack. */
     final boolean mUseDevInputEventForAudioJack;
 
-    public InputManagerService(Context context, Handler handler) {
+    public InputManagerService(Context context) {
         this.mContext = context;
-        this.mHandler = new InputManagerHandler(handler.getLooper());
+        this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());
 
         mUseDevInputEventForAudioJack =
                 context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
         Slog.i(TAG, "Initializing input manager, mUseDevInputEventForAudioJack="
                 + mUseDevInputEventForAudioJack);
         mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
+
+        LocalServices.addService(InputManagerInternal.class, new LocalService());
     }
 
     public void setWindowManagerCallbacks(WindowManagerCallbacks callbacks) {
@@ -329,8 +336,7 @@
         nativeReloadDeviceAliases(mPtr);
     }
 
-    @Override
-    public void setDisplayViewports(DisplayViewport defaultViewport,
+    private void setDisplayViewportsInternal(DisplayViewport defaultViewport,
             DisplayViewport externalTouchViewport) {
         if (defaultViewport.valid) {
             setDisplayViewport(false, defaultViewport);
@@ -378,7 +384,7 @@
     public int getScanCodeState(int deviceId, int sourceMask, int scanCode) {
         return nativeGetScanCodeState(mPtr, deviceId, sourceMask, scanCode);
     }
-    
+
     /**
      * Gets the current state of a switch by switch code.
      * @param deviceId The input device id, or -1 to consult all devices.
@@ -413,10 +419,10 @@
             throw new IllegalArgumentException("keyExists must not be null and must be at "
                     + "least as large as keyCodes.");
         }
-        
+
         return nativeHasKeys(mPtr, deviceId, sourceMask, keyCodes, keyExists);
     }
-    
+
     /**
      * Creates an input channel that will receive all input from the input dispatcher.
      * @param inputChannelName The input channel name.
@@ -426,7 +432,7 @@
         if (inputChannelName == null) {
             throw new IllegalArgumentException("inputChannelName must not be null.");
         }
-        
+
         InputChannel[] inputChannels = InputChannel.openInputChannelPair(inputChannelName);
         nativeRegisterInputChannel(mPtr, inputChannels[0], null, true);
         inputChannels[0].dispose(); // don't need to retain the Java object reference
@@ -444,10 +450,10 @@
         if (inputChannel == null) {
             throw new IllegalArgumentException("inputChannel must not be null.");
         }
-        
+
         nativeRegisterInputChannel(mPtr, inputChannel, inputWindowHandle, false);
     }
-    
+
     /**
      * Unregisters an input channel.
      * @param inputChannel The input channel to unregister.
@@ -456,7 +462,7 @@
         if (inputChannel == null) {
             throw new IllegalArgumentException("inputChannel must not be null.");
         }
-        
+
         nativeUnregisterInputChannel(mPtr, inputChannel);
     }
 
@@ -505,6 +511,10 @@
 
     @Override // Binder call
     public boolean injectInputEvent(InputEvent event, int mode) {
+        return injectInputEventInternal(event, Display.DEFAULT_DISPLAY, mode);
+    }
+
+    private boolean injectInputEventInternal(InputEvent event, int displayId, int mode) {
         if (event == null) {
             throw new IllegalArgumentException("event must not be null");
         }
@@ -519,7 +529,7 @@
         final long ident = Binder.clearCallingIdentity();
         final int result;
         try {
-            result = nativeInjectInputEvent(mPtr, event, pid, uid, mode,
+            result = nativeInjectInputEvent(mPtr, event, displayId, pid, uid, mode,
                     INJECTION_TIMEOUT_MILLIS, WindowManagerPolicy.FLAG_DISABLE_KEY_REPEAT);
         } finally {
             Binder.restoreCallingIdentity(ident);
@@ -894,35 +904,62 @@
         }
     }
 
-    @Override // Binder call
-    public String getCurrentKeyboardLayoutForInputDevice(String inputDeviceDescriptor) {
-        if (inputDeviceDescriptor == null) {
-            throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
+    /**
+     * Builds a layout descriptor for the vendor/product. This returns the
+     * descriptor for ids that aren't useful (such as the default 0, 0).
+     */
+    private String getLayoutDescriptor(InputDeviceIdentifier identifier) {
+        if (identifier == null || identifier.getDescriptor() == null) {
+            throw new IllegalArgumentException("identifier and descriptor must not be null");
         }
 
+        if (identifier.getVendorId() == 0 && identifier.getProductId() == 0) {
+            return identifier.getDescriptor();
+        }
+        StringBuilder bob = new StringBuilder();
+        bob.append("vendor:").append(identifier.getVendorId());
+        bob.append(",product:").append(identifier.getProductId());
+        return bob.toString();
+    }
+
+    @Override // Binder call
+    public String getCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier) {
+
+        String key = getLayoutDescriptor(identifier);
         synchronized (mDataStore) {
-            return mDataStore.getCurrentKeyboardLayout(inputDeviceDescriptor);
+            String layout = null;
+            // try loading it using the layout descriptor if we have it
+            layout = mDataStore.getCurrentKeyboardLayout(key);
+            if (layout == null && !key.equals(identifier.getDescriptor())) {
+                // if it doesn't exist fall back to the device descriptor
+                layout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor());
+            }
+            if (DEBUG) {
+                Slog.d(TAG, "Loaded keyboard layout id for " + key + " and got "
+                        + layout);
+            }
+            return layout;
         }
     }
 
     @Override // Binder call
-    public void setCurrentKeyboardLayoutForInputDevice(String inputDeviceDescriptor,
+    public void setCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
             String keyboardLayoutDescriptor) {
         if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
                 "setCurrentKeyboardLayoutForInputDevice()")) {
             throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
         }
-        if (inputDeviceDescriptor == null) {
-            throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
-        }
         if (keyboardLayoutDescriptor == null) {
             throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
         }
 
+        String key = getLayoutDescriptor(identifier);
         synchronized (mDataStore) {
             try {
-                if (mDataStore.setCurrentKeyboardLayout(
-                        inputDeviceDescriptor, keyboardLayoutDescriptor)) {
+                if (mDataStore.setCurrentKeyboardLayout(key, keyboardLayoutDescriptor)) {
+                    if (DEBUG) {
+                        Slog.d(TAG, "Saved keyboard layout using " + key);
+                    }
                     mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
                 }
             } finally {
@@ -932,36 +969,39 @@
     }
 
     @Override // Binder call
-    public String[] getKeyboardLayoutsForInputDevice(String inputDeviceDescriptor) {
-        if (inputDeviceDescriptor == null) {
-            throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
-        }
-
+    public String[] getKeyboardLayoutsForInputDevice(InputDeviceIdentifier identifier) {
+        String key = getLayoutDescriptor(identifier);
         synchronized (mDataStore) {
-            return mDataStore.getKeyboardLayouts(inputDeviceDescriptor);
+            String[] layouts = mDataStore.getKeyboardLayouts(key);
+            if ((layouts == null || layouts.length == 0)
+                    && !key.equals(identifier.getDescriptor())) {
+                layouts = mDataStore.getKeyboardLayouts(identifier.getDescriptor());
+            }
+            return layouts;
         }
     }
 
     @Override // Binder call
-    public void addKeyboardLayoutForInputDevice(String inputDeviceDescriptor,
+    public void addKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
             String keyboardLayoutDescriptor) {
         if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
                 "addKeyboardLayoutForInputDevice()")) {
             throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
         }
-        if (inputDeviceDescriptor == null) {
-            throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
-        }
         if (keyboardLayoutDescriptor == null) {
             throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
         }
 
+        String key = getLayoutDescriptor(identifier);
         synchronized (mDataStore) {
             try {
-                String oldLayout = mDataStore.getCurrentKeyboardLayout(inputDeviceDescriptor);
-                if (mDataStore.addKeyboardLayout(inputDeviceDescriptor, keyboardLayoutDescriptor)
+                String oldLayout = mDataStore.getCurrentKeyboardLayout(key);
+                if (oldLayout == null && !key.equals(identifier.getDescriptor())) {
+                    oldLayout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor());
+                }
+                if (mDataStore.addKeyboardLayout(key, keyboardLayoutDescriptor)
                         && !Objects.equal(oldLayout,
-                                mDataStore.getCurrentKeyboardLayout(inputDeviceDescriptor))) {
+                                mDataStore.getCurrentKeyboardLayout(key))) {
                     mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
                 }
             } finally {
@@ -971,26 +1011,31 @@
     }
 
     @Override // Binder call
-    public void removeKeyboardLayoutForInputDevice(String inputDeviceDescriptor,
+    public void removeKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
             String keyboardLayoutDescriptor) {
         if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
                 "removeKeyboardLayoutForInputDevice()")) {
             throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
         }
-        if (inputDeviceDescriptor == null) {
-            throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
-        }
         if (keyboardLayoutDescriptor == null) {
             throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
         }
 
+        String key = getLayoutDescriptor(identifier);
         synchronized (mDataStore) {
             try {
-                String oldLayout = mDataStore.getCurrentKeyboardLayout(inputDeviceDescriptor);
-                if (mDataStore.removeKeyboardLayout(inputDeviceDescriptor,
-                        keyboardLayoutDescriptor)
-                        && !Objects.equal(oldLayout,
-                                mDataStore.getCurrentKeyboardLayout(inputDeviceDescriptor))) {
+                String oldLayout = mDataStore.getCurrentKeyboardLayout(key);
+                if (oldLayout == null && !key.equals(identifier.getDescriptor())) {
+                    oldLayout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor());
+                }
+                boolean removed = mDataStore.removeKeyboardLayout(key, keyboardLayoutDescriptor);
+                if (!key.equals(identifier.getDescriptor())) {
+                    // We need to remove from both places to ensure it is gone
+                    removed |= mDataStore.removeKeyboardLayout(identifier.getDescriptor(),
+                            keyboardLayoutDescriptor);
+                }
+                if (removed && !Objects.equal(oldLayout,
+                                mDataStore.getCurrentKeyboardLayout(key))) {
                     mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
                 }
             } finally {
@@ -1007,14 +1052,15 @@
     private void handleSwitchKeyboardLayout(int deviceId, int direction) {
         final InputDevice device = getInputDevice(deviceId);
         if (device != null) {
-            final String inputDeviceDescriptor = device.getDescriptor();
             final boolean changed;
             final String keyboardLayoutDescriptor;
+
+            String key = getLayoutDescriptor(device.getIdentifier());
             synchronized (mDataStore) {
                 try {
-                    changed = mDataStore.switchKeyboardLayout(inputDeviceDescriptor, direction);
+                    changed = mDataStore.switchKeyboardLayout(key, direction);
                     keyboardLayoutDescriptor = mDataStore.getCurrentKeyboardLayout(
-                            inputDeviceDescriptor);
+                            key);
                 } finally {
                     mDataStore.saveIfNeeded();
                 }
@@ -1042,11 +1088,11 @@
     public void setInputWindows(InputWindowHandle[] windowHandles) {
         nativeSetInputWindows(mPtr, windowHandles);
     }
-    
+
     public void setFocusedApplication(InputApplicationHandle application) {
         nativeSetFocusedApplication(mPtr, application);
     }
-    
+
     public void setInputDispatchMode(boolean enabled, boolean frozen) {
         nativeSetInputDispatchMode(mPtr, enabled, frozen);
     }
@@ -1315,14 +1361,14 @@
     }
 
     // Native callback.
-    private int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn) {
-        return mWindowManagerCallbacks.interceptKeyBeforeQueueing(
-                event, policyFlags, isScreenOn);
+    private int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
+        return mWindowManagerCallbacks.interceptKeyBeforeQueueing(event, policyFlags);
     }
 
     // Native callback.
-    private int interceptMotionBeforeQueueingWhenScreenOff(int policyFlags) {
-        return mWindowManagerCallbacks.interceptMotionBeforeQueueingWhenScreenOff(policyFlags);
+    private int interceptWakeMotionBeforeQueueing(long whenNanos, int policyFlags) {
+        return mWindowManagerCallbacks.interceptWakeMotionBeforeQueueing(
+                whenNanos, policyFlags);
     }
 
     // Native callback.
@@ -1426,13 +1472,12 @@
     }
 
     // Native callback.
-    private String[] getKeyboardLayoutOverlay(String inputDeviceDescriptor) {
+    private String[] getKeyboardLayoutOverlay(InputDeviceIdentifier identifier) {
         if (!mSystemReady) {
             return null;
         }
 
-        String keyboardLayoutDescriptor = getCurrentKeyboardLayoutForInputDevice(
-                inputDeviceDescriptor);
+        String keyboardLayoutDescriptor = getCurrentKeyboardLayoutForInputDevice(identifier);
         if (keyboardLayoutDescriptor == null) {
             return null;
         }
@@ -1481,9 +1526,9 @@
         public long notifyANR(InputApplicationHandle inputApplicationHandle,
                 InputWindowHandle inputWindowHandle, String reason);
 
-        public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn);
+        public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags);
 
-        public int interceptMotionBeforeQueueingWhenScreenOff(int policyFlags);
+        public int interceptWakeMotionBeforeQueueing(long whenNanos, int policyFlags);
 
         public long interceptKeyBeforeDispatching(InputWindowHandle focus,
                 KeyEvent event, int policyFlags);
@@ -1549,7 +1594,7 @@
 
             synchronized (mInputFilterLock) {
                 if (!mDisconnected) {
-                    nativeInjectInputEvent(mPtr, event, 0, 0,
+                    nativeInjectInputEvent(mPtr, event, Display.DEFAULT_DISPLAY, 0, 0,
                             InputManager.INJECT_INPUT_EVENT_MODE_ASYNC, 0,
                             policyFlags | WindowManagerPolicy.FLAG_FILTERED);
                 }
@@ -1639,4 +1684,22 @@
             onVibratorTokenDied(this);
         }
     }
+
+    private final class LocalService extends InputManagerInternal {
+        @Override
+        public void setDisplayViewports(
+                DisplayViewport defaultViewport, DisplayViewport externalTouchViewport) {
+            setDisplayViewportsInternal(defaultViewport, externalTouchViewport);
+        }
+
+        @Override
+        public boolean injectInputEvent(InputEvent event, int displayId, int mode) {
+            return injectInputEventInternal(event, displayId, mode);
+        }
+
+        @Override
+        public void setInteractive(boolean interactive) {
+            nativeSetInteractive(mPtr, interactive);
+        }
+    }
 }
diff --git a/services/java/com/android/server/input/InputWindowHandle.java b/services/core/java/com/android/server/input/InputWindowHandle.java
similarity index 100%
rename from services/java/com/android/server/input/InputWindowHandle.java
rename to services/core/java/com/android/server/input/InputWindowHandle.java
diff --git a/services/java/com/android/server/input/PersistentDataStore.java b/services/core/java/com/android/server/input/PersistentDataStore.java
similarity index 100%
rename from services/java/com/android/server/input/PersistentDataStore.java
rename to services/core/java/com/android/server/input/PersistentDataStore.java
diff --git a/services/core/java/com/android/server/lights/Light.java b/services/core/java/com/android/server/lights/Light.java
new file mode 100644
index 0000000..b496b4c6
--- /dev/null
+++ b/services/core/java/com/android/server/lights/Light.java
@@ -0,0 +1,41 @@
+/*
+ * 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.lights;
+
+public abstract class Light {
+    public static final int LIGHT_FLASH_NONE = 0;
+    public static final int LIGHT_FLASH_TIMED = 1;
+    public static final int LIGHT_FLASH_HARDWARE = 2;
+
+    /**
+     * Light brightness is managed by a user setting.
+     */
+    public static final int BRIGHTNESS_MODE_USER = 0;
+
+    /**
+     * Light brightness is managed by a light sensor.
+     */
+    public static final int BRIGHTNESS_MODE_SENSOR = 1;
+
+    public abstract void setBrightness(int brightness);
+    public abstract void setBrightness(int brightness, int brightnessMode);
+    public abstract void setColor(int color);
+    public abstract void setFlashing(int color, int mode, int onMS, int offMS);
+    public abstract void pulse();
+    public abstract void pulse(int color, int onMS);
+    public abstract void turnOff();
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/lights/LightsManager.java b/services/core/java/com/android/server/lights/LightsManager.java
new file mode 100644
index 0000000..2f20509
--- /dev/null
+++ b/services/core/java/com/android/server/lights/LightsManager.java
@@ -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 com.android.server.lights;
+
+public abstract class LightsManager {
+    public static final int LIGHT_ID_BACKLIGHT = 0;
+    public static final int LIGHT_ID_KEYBOARD = 1;
+    public static final int LIGHT_ID_BUTTONS = 2;
+    public static final int LIGHT_ID_BATTERY = 3;
+    public static final int LIGHT_ID_NOTIFICATIONS = 4;
+    public static final int LIGHT_ID_ATTENTION = 5;
+    public static final int LIGHT_ID_BLUETOOTH = 6;
+    public static final int LIGHT_ID_WIFI = 7;
+    public static final int LIGHT_ID_COUNT = 8;
+
+    public abstract Light getLight(int id);
+}
diff --git a/services/java/com/android/server/LightsService.java b/services/core/java/com/android/server/lights/LightsService.java
similarity index 74%
rename from services/java/com/android/server/LightsService.java
rename to services/core/java/com/android/server/lights/LightsService.java
index e99a3a4..94cf668 100644
--- a/services/java/com/android/server/LightsService.java
+++ b/services/core/java/com/android/server/lights/LightsService.java
@@ -14,59 +14,38 @@
  * limitations under the License.
  */
 
-package com.android.server;
+package com.android.server.lights;
+
+import com.android.server.SystemService;
 
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.os.Handler;
 import android.os.IHardwareService;
-import android.os.ServiceManager;
 import android.os.Message;
 import android.util.Slog;
 
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
 
-public class LightsService {
-    private static final String TAG = "LightsService";
-    private static final boolean DEBUG = false;
+public class LightsService extends SystemService {
+    static final String TAG = "LightsService";
+    static final boolean DEBUG = false;
 
-    public static final int LIGHT_ID_BACKLIGHT = 0;
-    public static final int LIGHT_ID_KEYBOARD = 1;
-    public static final int LIGHT_ID_BUTTONS = 2;
-    public static final int LIGHT_ID_BATTERY = 3;
-    public static final int LIGHT_ID_NOTIFICATIONS = 4;
-    public static final int LIGHT_ID_ATTENTION = 5;
-    public static final int LIGHT_ID_BLUETOOTH = 6;
-    public static final int LIGHT_ID_WIFI = 7;
-    public static final int LIGHT_ID_COUNT = 8;
+    final LightImpl mLights[] = new LightImpl[LightsManager.LIGHT_ID_COUNT];
 
-    public static final int LIGHT_FLASH_NONE = 0;
-    public static final int LIGHT_FLASH_TIMED = 1;
-    public static final int LIGHT_FLASH_HARDWARE = 2;
+    private final class LightImpl extends Light {
 
-    /**
-     * Light brightness is managed by a user setting.
-     */
-    public static final int BRIGHTNESS_MODE_USER = 0;
-
-    /**
-     * Light brightness is managed by a light sensor.
-     */
-    public static final int BRIGHTNESS_MODE_SENSOR = 1;
-
-    private final Light mLights[] = new Light[LIGHT_ID_COUNT];
-
-    public final class Light {
-
-        private Light(int id) {
+        private LightImpl(int id) {
             mId = id;
         }
 
+        @Override
         public void setBrightness(int brightness) {
             setBrightness(brightness, BRIGHTNESS_MODE_USER);
         }
 
+        @Override
         public void setBrightness(int brightness, int brightnessMode) {
             synchronized (this) {
                 int color = brightness & 0x000000ff;
@@ -75,23 +54,26 @@
             }
         }
 
+        @Override
         public void setColor(int color) {
             synchronized (this) {
                 setLightLocked(color, LIGHT_FLASH_NONE, 0, 0, 0);
             }
         }
 
+        @Override
         public void setFlashing(int color, int mode, int onMS, int offMS) {
             synchronized (this) {
                 setLightLocked(color, mode, onMS, offMS, BRIGHTNESS_MODE_USER);
             }
         }
 
-
+        @Override
         public void pulse() {
             pulse(0x00ffffff, 7);
         }
 
+        @Override
         public void pulse(int color, int onMS) {
             synchronized (this) {
                 if (mColor == 0 && !mFlashing) {
@@ -102,6 +84,7 @@
             }
         }
 
+        @Override
         public void turnOff() {
             synchronized (this) {
                 setLightLocked(0, LIGHT_FLASH_NONE, 0, 0, 0);
@@ -154,9 +137,10 @@
         }
 
         public void setFlashlightEnabled(boolean on) {
-            if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.FLASHLIGHT)
+            final Context context = getContext();
+            if (context.checkCallingOrSelfPermission(android.Manifest.permission.FLASHLIGHT)
                     != PackageManager.PERMISSION_GRANTED &&
-                    mContext.checkCallingOrSelfPermission(android.Manifest.permission.HARDWARE_TEST)
+                    context.checkCallingOrSelfPermission(android.Manifest.permission.HARDWARE_TEST)
                     != PackageManager.PERMISSION_GRANTED) {
                 throw new SecurityException("Requires FLASHLIGHT or HARDWARE_TEST permission");
             }
@@ -173,31 +157,43 @@
         }
     };
 
-    LightsService(Context context) {
+    public LightsService(Context context) {
+        super(context);
 
         mNativePointer = init_native();
-        mContext = context;
 
-        ServiceManager.addService("hardware", mLegacyFlashlightHack);
-
-        for (int i = 0; i < LIGHT_ID_COUNT; i++) {
-            mLights[i] = new Light(i);
+        for (int i = 0; i < LightsManager.LIGHT_ID_COUNT; i++) {
+            mLights[i] = new LightImpl(i);
         }
     }
 
+    @Override
+    public void onStart() {
+        publishBinderService("hardware", mLegacyFlashlightHack);
+        publishLocalService(LightsManager.class, mService);
+    }
+
+    private final LightsManager mService = new LightsManager() {
+        @Override
+        public com.android.server.lights.Light getLight(int id) {
+            if (id < LIGHT_ID_COUNT) {
+                return mLights[id];
+            } else {
+                return null;
+            }
+        }
+    };
+
+    @Override
     protected void finalize() throws Throwable {
         finalize_native(mNativePointer);
         super.finalize();
     }
 
-    public Light getLight(int id) {
-        return mLights[id];
-    }
-
     private Handler mH = new Handler() {
         @Override
         public void handleMessage(Message msg) {
-            Light light = (Light)msg.obj;
+            LightImpl light = (LightImpl)msg.obj;
             light.stopFlashing();
         }
     };
@@ -205,10 +201,8 @@
     private static native long init_native();
     private static native void finalize_native(long ptr);
 
-    private static native void setLight_native(long ptr, int light, int color, int mode,
+    static native void setLight_native(long ptr, int light, int color, int mode,
             int onMS, int offMS, int brightnessMode);
 
-    private final Context mContext;
-
     private long mNativePointer;
 }
diff --git a/services/java/com/android/server/location/ComprehensiveCountryDetector.java b/services/core/java/com/android/server/location/ComprehensiveCountryDetector.java
similarity index 100%
rename from services/java/com/android/server/location/ComprehensiveCountryDetector.java
rename to services/core/java/com/android/server/location/ComprehensiveCountryDetector.java
diff --git a/services/java/com/android/server/location/CountryDetectorBase.java b/services/core/java/com/android/server/location/CountryDetectorBase.java
similarity index 100%
rename from services/java/com/android/server/location/CountryDetectorBase.java
rename to services/core/java/com/android/server/location/CountryDetectorBase.java
diff --git a/services/java/com/android/server/location/FlpHardwareProvider.java b/services/core/java/com/android/server/location/FlpHardwareProvider.java
similarity index 100%
rename from services/java/com/android/server/location/FlpHardwareProvider.java
rename to services/core/java/com/android/server/location/FlpHardwareProvider.java
diff --git a/services/java/com/android/server/location/FusedLocationHardwareSecure.java b/services/core/java/com/android/server/location/FusedLocationHardwareSecure.java
similarity index 100%
rename from services/java/com/android/server/location/FusedLocationHardwareSecure.java
rename to services/core/java/com/android/server/location/FusedLocationHardwareSecure.java
diff --git a/services/java/com/android/server/location/FusedProxy.java b/services/core/java/com/android/server/location/FusedProxy.java
similarity index 100%
rename from services/java/com/android/server/location/FusedProxy.java
rename to services/core/java/com/android/server/location/FusedProxy.java
diff --git a/services/java/com/android/server/location/GeocoderProxy.java b/services/core/java/com/android/server/location/GeocoderProxy.java
similarity index 100%
rename from services/java/com/android/server/location/GeocoderProxy.java
rename to services/core/java/com/android/server/location/GeocoderProxy.java
diff --git a/services/java/com/android/server/location/GeofenceManager.java b/services/core/java/com/android/server/location/GeofenceManager.java
similarity index 100%
rename from services/java/com/android/server/location/GeofenceManager.java
rename to services/core/java/com/android/server/location/GeofenceManager.java
diff --git a/services/java/com/android/server/location/GeofenceProxy.java b/services/core/java/com/android/server/location/GeofenceProxy.java
similarity index 100%
rename from services/java/com/android/server/location/GeofenceProxy.java
rename to services/core/java/com/android/server/location/GeofenceProxy.java
diff --git a/services/java/com/android/server/location/GeofenceState.java b/services/core/java/com/android/server/location/GeofenceState.java
similarity index 100%
rename from services/java/com/android/server/location/GeofenceState.java
rename to services/core/java/com/android/server/location/GeofenceState.java
diff --git a/services/java/com/android/server/location/GpsLocationProvider.java b/services/core/java/com/android/server/location/GpsLocationProvider.java
similarity index 100%
rename from services/java/com/android/server/location/GpsLocationProvider.java
rename to services/core/java/com/android/server/location/GpsLocationProvider.java
diff --git a/services/java/com/android/server/location/GpsXtraDownloader.java b/services/core/java/com/android/server/location/GpsXtraDownloader.java
similarity index 100%
rename from services/java/com/android/server/location/GpsXtraDownloader.java
rename to services/core/java/com/android/server/location/GpsXtraDownloader.java
diff --git a/services/java/com/android/server/location/LocationBasedCountryDetector.java b/services/core/java/com/android/server/location/LocationBasedCountryDetector.java
similarity index 100%
rename from services/java/com/android/server/location/LocationBasedCountryDetector.java
rename to services/core/java/com/android/server/location/LocationBasedCountryDetector.java
diff --git a/services/java/com/android/server/location/LocationBlacklist.java b/services/core/java/com/android/server/location/LocationBlacklist.java
similarity index 100%
rename from services/java/com/android/server/location/LocationBlacklist.java
rename to services/core/java/com/android/server/location/LocationBlacklist.java
diff --git a/services/java/com/android/server/location/LocationFudger.java b/services/core/java/com/android/server/location/LocationFudger.java
similarity index 100%
rename from services/java/com/android/server/location/LocationFudger.java
rename to services/core/java/com/android/server/location/LocationFudger.java
diff --git a/services/java/com/android/server/location/LocationProviderInterface.java b/services/core/java/com/android/server/location/LocationProviderInterface.java
similarity index 100%
rename from services/java/com/android/server/location/LocationProviderInterface.java
rename to services/core/java/com/android/server/location/LocationProviderInterface.java
diff --git a/services/java/com/android/server/location/LocationProviderProxy.java b/services/core/java/com/android/server/location/LocationProviderProxy.java
similarity index 100%
rename from services/java/com/android/server/location/LocationProviderProxy.java
rename to services/core/java/com/android/server/location/LocationProviderProxy.java
diff --git a/services/java/com/android/server/location/MockProvider.java b/services/core/java/com/android/server/location/MockProvider.java
similarity index 100%
rename from services/java/com/android/server/location/MockProvider.java
rename to services/core/java/com/android/server/location/MockProvider.java
diff --git a/services/java/com/android/server/location/PassiveProvider.java b/services/core/java/com/android/server/location/PassiveProvider.java
similarity index 100%
rename from services/java/com/android/server/location/PassiveProvider.java
rename to services/core/java/com/android/server/location/PassiveProvider.java
diff --git a/services/java/com/android/server/media/MediaRouterService.java b/services/core/java/com/android/server/media/MediaRouterService.java
similarity index 100%
rename from services/java/com/android/server/media/MediaRouterService.java
rename to services/core/java/com/android/server/media/MediaRouterService.java
diff --git a/services/java/com/android/server/media/RemoteDisplayProviderProxy.java b/services/core/java/com/android/server/media/RemoteDisplayProviderProxy.java
similarity index 100%
rename from services/java/com/android/server/media/RemoteDisplayProviderProxy.java
rename to services/core/java/com/android/server/media/RemoteDisplayProviderProxy.java
diff --git a/services/java/com/android/server/media/RemoteDisplayProviderWatcher.java b/services/core/java/com/android/server/media/RemoteDisplayProviderWatcher.java
similarity index 100%
rename from services/java/com/android/server/media/RemoteDisplayProviderWatcher.java
rename to services/core/java/com/android/server/media/RemoteDisplayProviderWatcher.java
diff --git a/services/java/com/android/server/net/LockdownVpnTracker.java b/services/core/java/com/android/server/net/LockdownVpnTracker.java
similarity index 100%
rename from services/java/com/android/server/net/LockdownVpnTracker.java
rename to services/core/java/com/android/server/net/LockdownVpnTracker.java
diff --git a/services/java/com/android/server/net/NetworkIdentitySet.java b/services/core/java/com/android/server/net/NetworkIdentitySet.java
similarity index 100%
rename from services/java/com/android/server/net/NetworkIdentitySet.java
rename to services/core/java/com/android/server/net/NetworkIdentitySet.java
diff --git a/services/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
similarity index 99%
rename from services/java/com/android/server/net/NetworkPolicyManagerService.java
rename to services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index eb7cc4c..855ae23 100644
--- a/services/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -1730,7 +1730,7 @@
     private void updateScreenOn() {
         synchronized (mRulesLock) {
             try {
-                mScreenOn = mPowerManager.isScreenOn();
+                mScreenOn = mPowerManager.isInteractive();
             } catch (RemoteException e) {
                 // ignored; service lives in system_server
             }
diff --git a/services/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java
similarity index 100%
rename from services/java/com/android/server/net/NetworkStatsCollection.java
rename to services/core/java/com/android/server/net/NetworkStatsCollection.java
diff --git a/services/java/com/android/server/net/NetworkStatsRecorder.java b/services/core/java/com/android/server/net/NetworkStatsRecorder.java
similarity index 100%
rename from services/java/com/android/server/net/NetworkStatsRecorder.java
rename to services/core/java/com/android/server/net/NetworkStatsRecorder.java
diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
similarity index 100%
rename from services/java/com/android/server/net/NetworkStatsService.java
rename to services/core/java/com/android/server/net/NetworkStatsService.java
diff --git a/services/core/java/com/android/server/notification/NotificationDelegate.java b/services/core/java/com/android/server/notification/NotificationDelegate.java
new file mode 100644
index 0000000..df2aaca
--- /dev/null
+++ b/services/core/java/com/android/server/notification/NotificationDelegate.java
@@ -0,0 +1,27 @@
+/**
+ * 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.notification;
+
+public interface NotificationDelegate {
+    void onSetDisabled(int status);
+    void onClearAll();
+    void onNotificationClick(String pkg, String tag, int id);
+    void onNotificationClear(String pkg, String tag, int id);
+    void onNotificationError(String pkg, String tag, int id,
+            int uid, int initialPid, String message);
+    void onPanelRevealed();
+}
diff --git a/services/java/com/android/server/power/DisplayBlanker.java b/services/core/java/com/android/server/notification/NotificationManagerInternal.java
similarity index 61%
copy from services/java/com/android/server/power/DisplayBlanker.java
copy to services/core/java/com/android/server/notification/NotificationManagerInternal.java
index 6072053..b695b68 100644
--- a/services/java/com/android/server/power/DisplayBlanker.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerInternal.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 The Android Open Source Project
+ * Copyright (C) 2014 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,12 +14,11 @@
  * limitations under the License.
  */
 
-package com.android.server.power;
+package com.android.server.notification;
 
-/**
- * Blanks or unblanks all displays.
- */
-interface DisplayBlanker {
-    public void blankAllDisplays();
-    public void unblankAllDisplays();
+import android.app.Notification;
+
+public interface NotificationManagerInternal {
+    void enqueueNotification(String pkg, String basePkg, int callingUid, int callingPid,
+            String tag, int id, Notification notification, int[] idReceived, int userId);
 }
diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
similarity index 75%
rename from services/java/com/android/server/NotificationManagerService.java
rename to services/core/java/com/android/server/notification/NotificationManagerService.java
index dedc9bd..38b8dc6 100644
--- a/services/java/com/android/server/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server;
+package com.android.server.notification;
 
 import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
 import static org.xmlpull.v1.XmlPullParser.END_TAG;
@@ -47,7 +47,6 @@
 import android.database.ContentObserver;
 import android.graphics.Bitmap;
 import android.media.AudioManager;
-import android.media.IAudioService;
 import android.media.IRingtonePlayer;
 import android.net.Uri;
 import android.os.Binder;
@@ -56,9 +55,7 @@
 import android.os.Message;
 import android.os.Process;
 import android.os.RemoteException;
-import android.os.ServiceManager;
 import android.os.UserHandle;
-import android.os.UserManager;
 import android.os.Vibrator;
 import android.provider.Settings;
 import android.service.notification.INotificationListener;
@@ -66,6 +63,7 @@
 import android.service.notification.StatusBarNotification;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
+import android.util.ArrayMap;
 import android.util.AtomicFile;
 import android.util.EventLog;
 import android.util.Log;
@@ -78,6 +76,12 @@
 import com.android.internal.R;
 
 import com.android.internal.notification.NotificationScorer;
+import com.android.server.EventLogTags;
+import com.android.server.statusbar.StatusBarManagerInternal;
+import com.android.server.SystemService;
+import com.android.server.lights.Light;
+import com.android.server.lights.LightsManager;
+
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -99,66 +103,61 @@
 
 import libcore.io.IoUtils;
 
-
 /** {@hide} */
-public class NotificationManagerService extends INotificationManager.Stub
-{
-    private static final String TAG = "NotificationService";
-    private static final boolean DBG = false;
+public class NotificationManagerService extends SystemService {
+    static final String TAG = "NotificationService";
+    static final boolean DBG = false;
 
-    private static final int MAX_PACKAGE_NOTIFICATIONS = 50;
+    static final int MAX_PACKAGE_NOTIFICATIONS = 50;
 
     // message codes
-    private static final int MESSAGE_TIMEOUT = 2;
+    static final int MESSAGE_TIMEOUT = 2;
 
-    private static final int LONG_DELAY = 3500; // 3.5 seconds
-    private static final int SHORT_DELAY = 2000; // 2 seconds
+    static final int LONG_DELAY = 3500; // 3.5 seconds
+    static final int SHORT_DELAY = 2000; // 2 seconds
 
-    private static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250};
-    private static final int VIBRATE_PATTERN_MAXLEN = 8 * 2 + 1; // up to eight bumps
+    static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250};
+    static final int VIBRATE_PATTERN_MAXLEN = 8 * 2 + 1; // up to eight bumps
 
-    private static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_NOTIFICATION;
-    private static final boolean SCORE_ONGOING_HIGHER = false;
+    static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_NOTIFICATION;
+    static final boolean SCORE_ONGOING_HIGHER = false;
 
-    private static final int JUNK_SCORE = -1000;
-    private static final int NOTIFICATION_PRIORITY_MULTIPLIER = 10;
-    private static final int SCORE_DISPLAY_THRESHOLD = Notification.PRIORITY_MIN * NOTIFICATION_PRIORITY_MULTIPLIER;
+    static final int JUNK_SCORE = -1000;
+    static final int NOTIFICATION_PRIORITY_MULTIPLIER = 10;
+    static final int SCORE_DISPLAY_THRESHOLD = Notification.PRIORITY_MIN * NOTIFICATION_PRIORITY_MULTIPLIER;
 
     // Notifications with scores below this will not interrupt the user, either via LED or
     // sound or vibration
-    private static final int SCORE_INTERRUPTION_THRESHOLD =
+    static final int SCORE_INTERRUPTION_THRESHOLD =
             Notification.PRIORITY_LOW * NOTIFICATION_PRIORITY_MULTIPLIER;
 
-    private static final boolean ENABLE_BLOCKED_NOTIFICATIONS = true;
-    private static final boolean ENABLE_BLOCKED_TOASTS = true;
+    static final boolean ENABLE_BLOCKED_NOTIFICATIONS = true;
+    static final boolean ENABLE_BLOCKED_TOASTS = true;
 
-    private static final String ENABLED_NOTIFICATION_LISTENERS_SEPARATOR = ":";
+    static final String ENABLED_NOTIFICATION_LISTENERS_SEPARATOR = ":";
 
-    final Context mContext;
-    final IActivityManager mAm;
-    final UserManager mUserManager;
+    private IActivityManager mAm;
+    AudioManager mAudioManager;
+    StatusBarManagerInternal mStatusBar;
+    Vibrator mVibrator;
+
     final IBinder mForegroundToken = new Binder();
-
     private WorkerHandler mHandler;
-    private StatusBarManagerService mStatusBar;
-    private LightsService.Light mNotificationLight;
-    private LightsService.Light mAttentionLight;
 
+    private Light mNotificationLight;
+    Light mAttentionLight;
     private int mDefaultNotificationColor;
     private int mDefaultNotificationLedOn;
+
     private int mDefaultNotificationLedOff;
-
     private long[] mDefaultVibrationPattern;
+
     private long[] mFallbackVibrationPattern;
+    boolean mSystemReady;
 
-    private boolean mSystemReady;
-    private int mDisabledNotifications;
-
-    private NotificationRecord mSoundNotification;
-    private NotificationRecord mVibrateNotification;
-
-    private IAudioService mAudioService;
-    private Vibrator mVibrator;
+    int mDisabledNotifications;
+    NotificationRecord mSoundNotification;
+    NotificationRecord mVibrateNotification;
 
     // for enabling and disabling notification pulse behavior
     private boolean mScreenOn = true;
@@ -166,15 +165,17 @@
     private boolean mNotificationPulseEnabled;
 
     // used as a mutex for access to all active notifications & listeners
-    private final ArrayList<NotificationRecord> mNotificationList =
+    final ArrayList<NotificationRecord> mNotificationList =
             new ArrayList<NotificationRecord>();
+    final ArrayMap<String, NotificationRecord> mNotificationsByKey =
+            new ArrayMap<String, NotificationRecord>();
 
-    private ArrayList<ToastRecord> mToastQueue;
+    final ArrayList<ToastRecord> mToastQueue = new ArrayList<ToastRecord>();
 
-    private ArrayList<NotificationRecord> mLights = new ArrayList<NotificationRecord>();
-    private NotificationRecord mLedNotification;
+    ArrayList<NotificationRecord> mLights = new ArrayList<NotificationRecord>();
+    NotificationRecord mLedNotification;
 
-    private final AppOpsManager mAppOps;
+    private AppOpsManager mAppOps;
 
     // contains connections to all connected listeners, including app services
     // and system listeners
@@ -202,9 +203,9 @@
     private static final String TAG_PACKAGE = "package";
     private static final String ATTR_NAME = "name";
 
-    private final ArrayList<NotificationScorer> mScorers = new ArrayList<NotificationScorer>();
+    final ArrayList<NotificationScorer> mScorers = new ArrayList<NotificationScorer>();
 
-    private class NotificationListenerInfo implements DeathRecipient {
+    private class NotificationListenerInfo implements IBinder.DeathRecipient {
         INotificationListener listener;
         ComponentName component;
         int userid;
@@ -401,12 +402,14 @@
                         tag = parser.getName();
                         if (type == START_TAG) {
                             if (TAG_BODY.equals(tag)) {
-                                version = Integer.parseInt(parser.getAttributeValue(null, ATTR_VERSION));
+                                version = Integer.parseInt(
+                                        parser.getAttributeValue(null, ATTR_VERSION));
                             } else if (TAG_BLOCKED_PKGS.equals(tag)) {
                                 while ((type = parser.next()) != END_DOCUMENT) {
                                     tag = parser.getName();
                                     if (TAG_PACKAGE.equals(tag)) {
-                                        mBlockedPackages.add(parser.getAttributeValue(null, ATTR_NAME));
+                                        mBlockedPackages.add(
+                                                parser.getAttributeValue(null, ATTR_NAME));
                                     } else if (TAG_BLOCKED_PKGS.equals(tag) && type == END_TAG) {
                                         break;
                                     }
@@ -429,15 +432,6 @@
         }
     }
 
-    /**
-     * Use this when you just want to know if notifications are OK for this package.
-     */
-    public boolean areNotificationsEnabledForPackage(String pkg, int uid) {
-        checkCallerIsSystem();
-        return (mAppOps.checkOpNoThrow(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg)
-                == AppOpsManager.MODE_ALLOWED);
-    }
-
     /** Use this when you actually want to post a notification or toast.
      *
      * Unchecked. Not exposed via Binder, but can be called in the course of enqueue*().
@@ -451,21 +445,6 @@
         return true;
     }
 
-    public void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) {
-        checkCallerIsSystem();
-
-        Slog.v(TAG, (enabled?"en":"dis") + "abling notifications for " + pkg);
-
-        mAppOps.setMode(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg,
-                enabled ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED);
-
-        // Now, cancel any outstanding notifications that are part of a just-disabled app
-        if (ENABLE_BLOCKED_NOTIFICATIONS && !enabled) {
-            cancelAllNotificationsInt(pkg, 0, 0, true, UserHandle.getUserId(uid));
-        }
-    }
-
-
     private static String idDebugString(Context baseContext, String packageName, int id) {
         Context c = null;
 
@@ -491,57 +470,6 @@
         }
     }
 
-    /**
-     * System-only API for getting a list of current (i.e. not cleared) notifications.
-     *
-     * Requires ACCESS_NOTIFICATIONS which is signature|system.
-     */
-    @Override
-    public StatusBarNotification[] getActiveNotifications(String callingPkg) {
-        // enforce() will ensure the calling uid has the correct permission
-        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_NOTIFICATIONS,
-                "NotificationManagerService.getActiveNotifications");
-
-        StatusBarNotification[] tmp = null;
-        int uid = Binder.getCallingUid();
-
-        // noteOp will check to make sure the callingPkg matches the uid
-        if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
-                == AppOpsManager.MODE_ALLOWED) {
-            synchronized (mNotificationList) {
-                tmp = new StatusBarNotification[mNotificationList.size()];
-                final int N = mNotificationList.size();
-                for (int i=0; i<N; i++) {
-                    tmp[i] = mNotificationList.get(i).sbn;
-                }
-            }
-        }
-        return tmp;
-    }
-
-    /**
-     * System-only API for getting a list of recent (cleared, no longer shown) notifications.
-     *
-     * Requires ACCESS_NOTIFICATIONS which is signature|system.
-     */
-    @Override
-    public StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count) {
-        // enforce() will ensure the calling uid has the correct permission
-        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_NOTIFICATIONS,
-                "NotificationManagerService.getHistoricalNotifications");
-
-        StatusBarNotification[] tmp = null;
-        int uid = Binder.getCallingUid();
-
-        // noteOp will check to make sure the callingPkg matches the uid
-        if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
-                == AppOpsManager.MODE_ALLOWED) {
-            synchronized (mArchive) {
-                tmp = mArchive.getArray(count);
-            }
-        }
-        return tmp;
-    }
 
     /**
      * Remove notification access for any services that no longer exist.
@@ -549,12 +477,12 @@
     void disableNonexistentListeners() {
         int currentUser = ActivityManager.getCurrentUser();
         String flatIn = Settings.Secure.getStringForUser(
-                mContext.getContentResolver(),
+                getContext().getContentResolver(),
                 Settings.Secure.ENABLED_NOTIFICATION_LISTENERS,
                 currentUser);
         if (!TextUtils.isEmpty(flatIn)) {
             if (DBG) Slog.v(TAG, "flat before: " + flatIn);
-            PackageManager pm = mContext.getPackageManager();
+            PackageManager pm = getContext().getPackageManager();
             List<ResolveInfo> installedServices = pm.queryIntentServicesAsUser(
                     new Intent(NotificationListenerService.SERVICE_INTERFACE),
                     PackageManager.GET_SERVICES | PackageManager.GET_META_DATA,
@@ -590,7 +518,7 @@
             }
             if (DBG) Slog.v(TAG, "flat after: " + flatOut);
             if (!flatIn.equals(flatOut)) {
-                Settings.Secure.putStringForUser(mContext.getContentResolver(),
+                Settings.Secure.putStringForUser(getContext().getContentResolver(),
                         Settings.Secure.ENABLED_NOTIFICATION_LISTENERS,
                         flatOut, currentUser);
             }
@@ -604,7 +532,7 @@
     void rebindListenerServices() {
         final int currentUser = ActivityManager.getCurrentUser();
         String flat = Settings.Secure.getStringForUser(
-                mContext.getContentResolver(),
+                getContext().getContentResolver(),
                 Settings.Secure.ENABLED_NOTIFICATION_LISTENERS,
                 currentUser);
 
@@ -653,28 +581,6 @@
         }
     }
 
-    /**
-     * Register a listener binder directly with the notification manager.
-     *
-     * Only works with system callers. Apps should extend
-     * {@link android.service.notification.NotificationListenerService}.
-     */
-    @Override
-    public void registerListener(final INotificationListener listener,
-            final ComponentName component, final int userid) {
-        checkCallerIsSystem();
-
-        synchronized (mNotificationList) {
-            try {
-                NotificationListenerInfo info
-                        = new NotificationListenerInfo(listener, component, userid, true);
-                listener.asBinder().linkToDeath(info, 0);
-                mListeners.add(info);
-            } catch (RemoteException e) {
-                // already dead
-            }
-        }
-    }
 
     /**
      * Version of registerListener that takes the name of a
@@ -704,7 +610,7 @@
                     if (DBG) Slog.v(TAG, "    disconnecting old listener: " + info.listener);
                     mListeners.remove(i);
                     if (info.connection != null) {
-                        mContext.unbindService(info.connection);
+                        getContext().unbindService(info.connection);
                     }
                 }
             }
@@ -714,28 +620,42 @@
 
             intent.putExtra(Intent.EXTRA_CLIENT_LABEL,
                     R.string.notification_listener_binding_label);
-            intent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity(
-                    mContext, 0, new Intent(Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS), 0));
+
+            final PendingIntent pendingIntent = PendingIntent.getActivity(
+                    getContext(), 0, new Intent(Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS), 0);
+            intent.putExtra(Intent.EXTRA_CLIENT_INTENT, pendingIntent);
 
             try {
                 if (DBG) Slog.v(TAG, "binding: " + intent);
-                if (!mContext.bindServiceAsUser(intent,
+                if (!getContext().bindServiceAsUser(intent,
                         new ServiceConnection() {
                             INotificationListener mListener;
+
                             @Override
                             public void onServiceConnected(ComponentName name, IBinder service) {
+                                boolean added = false;
                                 synchronized (mNotificationList) {
                                     mServicesBinding.remove(servicesBindingTag);
                                     try {
                                         mListener = INotificationListener.Stub.asInterface(service);
-                                        NotificationListenerInfo info = new NotificationListenerInfo(
+                                        NotificationListenerInfo info
+                                                = new NotificationListenerInfo(
                                                 mListener, name, userid, this);
                                         service.linkToDeath(info, 0);
-                                        mListeners.add(info);
+                                        added = mListeners.add(info);
                                     } catch (RemoteException e) {
                                         // already dead
                                     }
                                 }
+                                if (added) {
+                                    final String[] keys =
+                                            getActiveNotificationKeysFromListener(mListener);
+                                    try {
+                                        mListener.onListenerConnected(keys);
+                                    } catch (RemoteException e) {
+                                        // we tried
+                                    }
+                                }
                             }
 
                             @Override
@@ -757,38 +677,6 @@
         }
     }
 
-    /**
-     * Removes a listener from the list and unbinds from its service.
-     */
-    public void unregisterListener(final INotificationListener listener, final int userid) {
-        if (listener == null) return;
-
-        NotificationListenerInfo info = removeListenerImpl(listener, userid);
-        if (info != null && info.connection != null) {
-            mContext.unbindService(info.connection);
-        }
-    }
-
-    /**
-     * Removes a listener from the list but does not unbind from the listener's service.
-     *
-     * @return the removed listener.
-     */
-    NotificationListenerInfo removeListenerImpl(
-            final INotificationListener listener, final int userid) {
-        NotificationListenerInfo listenerInfo = null;
-        synchronized (mNotificationList) {
-            final int N = mListeners.size();
-            for (int i=N-1; i>=0; i--) {
-                final NotificationListenerInfo info = mListeners.get(i);
-                if (info.listener.asBinder() == listener.asBinder()
-                        && info.userid == userid) {
-                    listenerInfo = mListeners.remove(i);
-                }
-            }
-        }
-        return listenerInfo;
-    }
 
     /**
      * Remove a listener service for the given user by ComponentName
@@ -805,7 +693,7 @@
                     mListeners.remove(i);
                     if (info.connection != null) {
                         try {
-                            mContext.unbindService(info.connection);
+                            getContext().unbindService(info.connection);
                         } catch (IllegalArgumentException ex) {
                             // something happened to the service: we think we have a connection
                             // but it's bogus.
@@ -820,7 +708,7 @@
     /**
      * asynchronously notify all listeners about a new notification
      */
-    private void notifyPostedLocked(NotificationRecord n) {
+    void notifyPostedLocked(NotificationRecord n) {
         // make a copy in case changes are made to the underlying Notification object
         final StatusBarNotification sbn = n.sbn.clone();
         for (final NotificationListenerInfo info : mListeners) {
@@ -835,7 +723,7 @@
     /**
      * asynchronously notify all listeners about a removed notification
      */
-    private void notifyRemovedLocked(NotificationRecord n) {
+    void notifyRemovedLocked(NotificationRecord n) {
         // make a copy in case changes are made to the underlying Notification object
         // NOTE: this copy is lightweight: it doesn't include heavyweight parts of the notification
         final StatusBarNotification sbn_light = n.sbn.cloneLight();
@@ -851,7 +739,14 @@
 
     // -- APIs to support listeners clicking/clearing notifications --
 
-    private NotificationListenerInfo checkListenerToken(INotificationListener listener) {
+    private void checkNullListener(INotificationListener listener) {
+        if (listener == null) {
+            throw new IllegalArgumentException("Listener must not be null");
+        }
+    }
+
+    private NotificationListenerInfo checkListenerTokenLocked(INotificationListener listener) {
+        checkNullListener(listener);
         final IBinder token = listener.asBinder();
         final int N = mListeners.size();
         for (int i=0; i<N; i++) {
@@ -861,66 +756,7 @@
         throw new SecurityException("Disallowed call from unknown listener: " + listener);
     }
 
-    /**
-     * Allow an INotificationListener to simulate a "clear all" operation.
-     *
-     * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onClearAllNotifications}
-     *
-     * @param token The binder for the listener, to check that the caller is allowed
-     */
-    public void cancelAllNotificationsFromListener(INotificationListener token) {
-        NotificationListenerInfo info = checkListenerToken(token);
-        long identity = Binder.clearCallingIdentity();
-        try {
-            cancelAll(info.userid);
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-    }
 
-    /**
-     * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
-     *
-     * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
-     *
-     * @param token The binder for the listener, to check that the caller is allowed
-     */
-    public void cancelNotificationFromListener(INotificationListener token, String pkg, String tag, int id) {
-        NotificationListenerInfo info = checkListenerToken(token);
-        long identity = Binder.clearCallingIdentity();
-        try {
-            cancelNotification(pkg, tag, id, 0,
-                    Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
-                    true,
-                    info.userid);
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-    }
-
-    /**
-     * Allow an INotificationListener to request the list of outstanding notifications seen by
-     * the current user. Useful when starting up, after which point the listener callbacks should
-     * be used.
-     *
-     * @param token The binder for the listener, to check that the caller is allowed
-     */
-    public StatusBarNotification[] getActiveNotificationsFromListener(INotificationListener token) {
-        NotificationListenerInfo info = checkListenerToken(token);
-
-        StatusBarNotification[] result = new StatusBarNotification[0];
-        ArrayList<StatusBarNotification> list = new ArrayList<StatusBarNotification>();
-        synchronized (mNotificationList) {
-            final int N = mNotificationList.size();
-            for (int i=0; i<N; i++) {
-                StatusBarNotification sbn = mNotificationList.get(i).sbn;
-                if (info.enabledAndUserMatches(sbn)) {
-                    list.add(sbn);
-                }
-            }
-        }
-        return list.toArray(result);
-    }
 
     // -- end of listener APIs --
 
@@ -945,6 +781,7 @@
             pw.println(prefix + "  icon=0x" + Integer.toHexString(notification.icon)
                     + " / " + idDebugString(baseContext, sbn.getPackageName(), notification.icon));
             pw.println(prefix + "  pri=" + notification.priority + " score=" + sbn.getScore());
+            pw.println(prefix + "  key=" + sbn.getKey());
             pw.println(prefix + "  contentIntent=" + notification.contentIntent);
             pw.println(prefix + "  deleteIntent=" + notification.deleteIntent);
             pw.println(prefix + "  tickerText=" + notification.tickerText);
@@ -1001,10 +838,11 @@
         @Override
         public final String toString() {
             return String.format(
-                    "NotificationRecord(0x%08x: pkg=%s user=%s id=%d tag=%s score=%d: %s)",
+                    "NotificationRecord(0x%08x: pkg=%s user=%s id=%d tag=%s score=%d key=%s: %s)",
                     System.identityHashCode(this),
-                    this.sbn.getPackageName(), this.sbn.getUser(), this.sbn.getId(), this.sbn.getTag(),
-                    this.sbn.getScore(), this.sbn.getNotification());
+                    this.sbn.getPackageName(), this.sbn.getUser(), this.sbn.getId(),
+                    this.sbn.getTag(), this.sbn.getScore(), this.sbn.getKey(),
+                    this.sbn.getNotification());
         }
     }
 
@@ -1042,9 +880,9 @@
         }
     }
 
-    private StatusBarManagerService.NotificationCallbacks mNotificationCallbacks
-            = new StatusBarManagerService.NotificationCallbacks() {
+    private final NotificationDelegate mNotificationDelegate = new NotificationDelegate() {
 
+        @Override
         public void onSetDisabled(int status) {
             synchronized (mNotificationList) {
                 mDisabledNotifications = status;
@@ -1052,7 +890,7 @@
                     // cancel whatever's going on
                     long identity = Binder.clearCallingIdentity();
                     try {
-                        final IRingtonePlayer player = mAudioService.getRingtonePlayer();
+                        final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
                         if (player != null) {
                             player.stopAsync();
                         }
@@ -1071,12 +909,17 @@
             }
         }
 
+        @Override
         public void onClearAll() {
             // XXX to be totally correct, the caller should tell us which user
             // this is for.
-            cancelAll(ActivityManager.getCurrentUser());
+            int currentUser = ActivityManager.getCurrentUser();
+            synchronized (mNotificationList) {
+                cancelAllLocked(currentUser);
+            }
         }
 
+        @Override
         public void onNotificationClick(String pkg, String tag, int id) {
             // XXX to be totally correct, the caller should tell us which user
             // this is for.
@@ -1085,6 +928,7 @@
                     ActivityManager.getCurrentUser());
         }
 
+        @Override
         public void onNotificationClear(String pkg, String tag, int id) {
             // XXX to be totally correct, the caller should tell us which user
             // this is for.
@@ -1093,6 +937,7 @@
                 true, ActivityManager.getCurrentUser());
         }
 
+        @Override
         public void onPanelRevealed() {
             synchronized (mNotificationList) {
                 // sound
@@ -1100,7 +945,7 @@
 
                 long identity = Binder.clearCallingIdentity();
                 try {
-                    final IRingtonePlayer player = mAudioService.getRingtonePlayer();
+                    final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
                     if (player != null) {
                         player.stopAsync();
                     }
@@ -1125,6 +970,7 @@
             }
         }
 
+        @Override
         public void onNotificationError(String pkg, String tag, int id,
                 int uid, int initialPid, String message) {
             Slog.d(TAG, "onNotification error pkg=" + pkg + " tag=" + tag + " id=" + id
@@ -1179,7 +1025,7 @@
                     if (packageChanged) {
                         // We cancel notifications for packages which have just been disabled
                         try {
-                            final int enabled = mContext.getPackageManager()
+                            final int enabled = getContext().getPackageManager()
                                     .getApplicationEnabledSetting(pkgName);
                             if (enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED
                                     || enabled == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
@@ -1255,7 +1101,7 @@
         }
 
         void observe() {
-            ContentResolver resolver = mContext.getContentResolver();
+            ContentResolver resolver = getContext().getContentResolver();
             resolver.registerContentObserver(NOTIFICATION_LIGHT_PULSE_URI,
                     false, this, UserHandle.USER_ALL);
             resolver.registerContentObserver(ENABLED_NOTIFICATION_LISTENERS_URI,
@@ -1268,7 +1114,7 @@
         }
 
         public void update(Uri uri) {
-            ContentResolver resolver = mContext.getContentResolver();
+            ContentResolver resolver = getContext().getContentResolver();
             if (uri == null || NOTIFICATION_LIGHT_PULSE_URI.equals(uri)) {
                 boolean pulseEnabled = Settings.System.getInt(resolver,
                             Settings.System.NOTIFICATION_LIGHT_PULSE, 0) != 0;
@@ -1298,28 +1144,28 @@
         return out;
     }
 
-    NotificationManagerService(Context context, StatusBarManagerService statusBar,
-            LightsService lights)
-    {
-        super();
-        mContext = context;
-        mVibrator = (Vibrator)context.getSystemService(Context.VIBRATOR_SERVICE);
-        mAm = ActivityManagerNative.getDefault();
-        mUserManager = (UserManager)context.getSystemService(Context.USER_SERVICE);
-        mToastQueue = new ArrayList<ToastRecord>();
-        mHandler = new WorkerHandler();
+    public NotificationManagerService(Context context) {
+        super(context);
+    }
 
-        mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
+    @Override
+    public void onStart() {
+        mAm = ActivityManagerNative.getDefault();
+        mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
+        mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
+
+        mHandler = new WorkerHandler();
 
         importOldBlockDb();
 
-        mStatusBar = statusBar;
-        statusBar.setNotificationCallbacks(mNotificationCallbacks);
+        mStatusBar = getLocalService(StatusBarManagerInternal.class);
+        mStatusBar.setNotificationDelegate(mNotificationDelegate);
 
-        mNotificationLight = lights.getLight(LightsService.LIGHT_ID_NOTIFICATIONS);
-        mAttentionLight = lights.getLight(LightsService.LIGHT_ID_ATTENTION);
+        final LightsManager lights = getLocalService(LightsManager.class);
+        mNotificationLight = lights.getLight(LightsManager.LIGHT_ID_NOTIFICATIONS);
+        mAttentionLight = lights.getLight(LightsManager.LIGHT_ID_ATTENTION);
 
-        Resources resources = mContext.getResources();
+        Resources resources = getContext().getResources();
         mDefaultNotificationColor = resources.getColor(
                 R.color.config_defaultNotificationColor);
         mDefaultNotificationLedOn = resources.getInteger(
@@ -1341,7 +1187,7 @@
         // After that, including subsequent boots, init with notifications turned on.
         // This works on the first boot because the setup wizard will toggle this
         // flag at least once and we'll go back to 0 after that.
-        if (0 == Settings.Global.getInt(mContext.getContentResolver(),
+        if (0 == Settings.Global.getInt(getContext().getContentResolver(),
                     Settings.Global.DEVICE_PROVISIONED, 0)) {
             mDisabledNotifications = StatusBarManager.DISABLE_NOTIFICATION_ALERTS;
         }
@@ -1354,7 +1200,7 @@
         filter.addAction(Intent.ACTION_USER_PRESENT);
         filter.addAction(Intent.ACTION_USER_STOPPED);
         filter.addAction(Intent.ACTION_USER_SWITCHED);
-        mContext.registerReceiver(mIntentReceiver, filter);
+        getContext().registerReceiver(mIntentReceiver, filter);
         IntentFilter pkgFilter = new IntentFilter();
         pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
         pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
@@ -1362,21 +1208,20 @@
         pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
         pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
         pkgFilter.addDataScheme("package");
-        mContext.registerReceiver(mIntentReceiver, pkgFilter);
+        getContext().registerReceiver(mIntentReceiver, pkgFilter);
         IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
-        mContext.registerReceiver(mIntentReceiver, sdFilter);
+        getContext().registerReceiver(mIntentReceiver, sdFilter);
 
         mSettingsObserver = new SettingsObserver(mHandler);
-        mSettingsObserver.observe();
 
         // spin up NotificationScorers
         String[] notificationScorerNames = resources.getStringArray(
                 R.array.config_notificationScorers);
         for (String scorerName : notificationScorerNames) {
             try {
-                Class<?> scorerClass = mContext.getClassLoader().loadClass(scorerName);
+                Class<?> scorerClass = getContext().getClassLoader().loadClass(scorerName);
                 NotificationScorer scorer = (NotificationScorer) scorerClass.newInstance();
-                scorer.initialize(mContext);
+                scorer.initialize(getContext());
                 mScorers.add(scorer);
             } catch (ClassNotFoundException e) {
                 Slog.w(TAG, "Couldn't find scorer " + scorerName + ".", e);
@@ -1386,6 +1231,9 @@
                 Slog.w(TAG, "Problem accessing scorer " + scorerName + ".", e);
             }
         }
+
+        publishBinderService(Context.NOTIFICATION_SERVICE, mService);
+        publishLocalService(NotificationManagerInternal.class, mInternalService);
     }
 
     /**
@@ -1394,12 +1242,12 @@
     private void importOldBlockDb() {
         loadBlockDb();
 
-        PackageManager pm = mContext.getPackageManager();
+        PackageManager pm = getContext().getPackageManager();
         for (String pkg : mBlockedPackages) {
             PackageInfo info = null;
             try {
                 info = pm.getPackageInfo(pkg, 0);
-                setNotificationsEnabledForPackage(pkg, info.applicationInfo.uid, false);
+                setNotificationsEnabledForPackageImpl(pkg, info.applicationInfo.uid, false);
             } catch (NameNotFoundException e) {
                 // forget you
             }
@@ -1410,244 +1258,475 @@
         }
     }
 
-    void systemReady() {
-        mAudioService = IAudioService.Stub.asInterface(
-                ServiceManager.getService(Context.AUDIO_SERVICE));
+    @Override
+    public void onBootPhase(int phase) {
+        if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
+            // no beeping until we're basically done booting
+            mSystemReady = true;
 
-        // no beeping until we're basically done booting
-        mSystemReady = true;
+            // Grab our optional AudioService
+            mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
 
-        // make sure our listener services are properly bound
-        rebindListenerServices();
+        } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
+            // This observer will force an update when observe is called, causing us to
+            // bind to listener services.
+            mSettingsObserver.observe();
+        }
     }
 
-    // Toasts
-    // ============================================================================
-    public void enqueueToast(String pkg, ITransientNotification callback, int duration)
-    {
-        if (DBG) Slog.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback + " duration=" + duration);
+    void setNotificationsEnabledForPackageImpl(String pkg, int uid, boolean enabled) {
+        Slog.v(TAG, (enabled?"en":"dis") + "abling notifications for " + pkg);
 
-        if (pkg == null || callback == null) {
-            Slog.e(TAG, "Not doing toast. pkg=" + pkg + " callback=" + callback);
-            return ;
+        mAppOps.setMode(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg,
+                enabled ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED);
+
+        // Now, cancel any outstanding notifications that are part of a just-disabled app
+        if (ENABLE_BLOCKED_NOTIFICATIONS && !enabled) {
+            cancelAllNotificationsInt(pkg, 0, 0, true, UserHandle.getUserId(uid));
         }
+    }
 
-        final boolean isSystemToast = isCallerSystem() || ("android".equals(pkg));
+    private final IBinder mService = new INotificationManager.Stub() {
+        // Toasts
+        // ============================================================================
 
-        if (ENABLE_BLOCKED_TOASTS && !noteNotificationOp(pkg, Binder.getCallingUid())) {
-            if (!isSystemToast) {
-                Slog.e(TAG, "Suppressing toast from package " + pkg + " by user request.");
-                return;
+        @Override
+        public void enqueueToast(String pkg, ITransientNotification callback, int duration)
+        {
+            if (DBG) {
+                Slog.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback
+                        + " duration=" + duration);
+            }
+
+            if (pkg == null || callback == null) {
+                Slog.e(TAG, "Not doing toast. pkg=" + pkg + " callback=" + callback);
+                return ;
+            }
+
+            final boolean isSystemToast = isCallerSystem() || ("android".equals(pkg));
+
+            if (ENABLE_BLOCKED_TOASTS && !noteNotificationOp(pkg, Binder.getCallingUid())) {
+                if (!isSystemToast) {
+                    Slog.e(TAG, "Suppressing toast from package " + pkg + " by user request.");
+                    return;
+                }
+            }
+
+            synchronized (mToastQueue) {
+                int callingPid = Binder.getCallingPid();
+                long callingId = Binder.clearCallingIdentity();
+                try {
+                    ToastRecord record;
+                    int index = indexOfToastLocked(pkg, callback);
+                    // If it's already in the queue, we update it in place, we don't
+                    // move it to the end of the queue.
+                    if (index >= 0) {
+                        record = mToastQueue.get(index);
+                        record.update(duration);
+                    } else {
+                        // Limit the number of toasts that any given package except the android
+                        // package can enqueue.  Prevents DOS attacks and deals with leaks.
+                        if (!isSystemToast) {
+                            int count = 0;
+                            final int N = mToastQueue.size();
+                            for (int i=0; i<N; i++) {
+                                 final ToastRecord r = mToastQueue.get(i);
+                                 if (r.pkg.equals(pkg)) {
+                                     count++;
+                                     if (count >= MAX_PACKAGE_NOTIFICATIONS) {
+                                         Slog.e(TAG, "Package has already posted " + count
+                                                + " toasts. Not showing more. Package=" + pkg);
+                                         return;
+                                     }
+                                 }
+                            }
+                        }
+
+                        record = new ToastRecord(callingPid, pkg, callback, duration);
+                        mToastQueue.add(record);
+                        index = mToastQueue.size() - 1;
+                        keepProcessAliveLocked(callingPid);
+                    }
+                    // If it's at index 0, it's the current toast.  It doesn't matter if it's
+                    // new or just been updated.  Call back and tell it to show itself.
+                    // If the callback fails, this will remove it from the list, so don't
+                    // assume that it's valid after this.
+                    if (index == 0) {
+                        showNextToastLocked();
+                    }
+                } finally {
+                    Binder.restoreCallingIdentity(callingId);
+                }
             }
         }
 
-        synchronized (mToastQueue) {
-            int callingPid = Binder.getCallingPid();
-            long callingId = Binder.clearCallingIdentity();
+        @Override
+        public void cancelToast(String pkg, ITransientNotification callback) {
+            Slog.i(TAG, "cancelToast pkg=" + pkg + " callback=" + callback);
+
+            if (pkg == null || callback == null) {
+                Slog.e(TAG, "Not cancelling notification. pkg=" + pkg + " callback=" + callback);
+                return ;
+            }
+
+            synchronized (mToastQueue) {
+                long callingId = Binder.clearCallingIdentity();
+                try {
+                    int index = indexOfToastLocked(pkg, callback);
+                    if (index >= 0) {
+                        cancelToastLocked(index);
+                    } else {
+                        Slog.w(TAG, "Toast already cancelled. pkg=" + pkg
+                                + " callback=" + callback);
+                    }
+                } finally {
+                    Binder.restoreCallingIdentity(callingId);
+                }
+            }
+        }
+
+        @Override
+        public void enqueueNotificationWithTag(String pkg, String basePkg, String tag, int id,
+                Notification notification, int[] idOut, int userId) throws RemoteException {
+            enqueueNotificationInternal(pkg, basePkg, Binder.getCallingUid(),
+                    Binder.getCallingPid(), tag, id, notification, idOut, userId);
+        }
+
+        @Override
+        public void cancelNotificationWithTag(String pkg, String tag, int id, int userId) {
+            checkCallerIsSystemOrSameApp(pkg);
+            userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
+                    Binder.getCallingUid(), userId, true, false, "cancelNotificationWithTag", pkg);
+            // Don't allow client applications to cancel foreground service notis.
+            cancelNotification(pkg, tag, id, 0,
+                    Binder.getCallingUid() == Process.SYSTEM_UID
+                    ? 0 : Notification.FLAG_FOREGROUND_SERVICE, false, userId);
+        }
+
+        @Override
+        public void cancelAllNotifications(String pkg, int userId) {
+            checkCallerIsSystemOrSameApp(pkg);
+
+            userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
+                    Binder.getCallingUid(), userId, true, false, "cancelAllNotifications", pkg);
+
+            // Calling from user space, don't allow the canceling of actively
+            // running foreground services.
+            cancelAllNotificationsInt(pkg, 0, Notification.FLAG_FOREGROUND_SERVICE, true, userId);
+        }
+
+        @Override
+        public void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) {
+            checkCallerIsSystem();
+
+            setNotificationsEnabledForPackageImpl(pkg, uid, enabled);
+        }
+
+        /**
+         * Use this when you just want to know if notifications are OK for this package.
+         */
+        @Override
+        public boolean areNotificationsEnabledForPackage(String pkg, int uid) {
+            checkCallerIsSystem();
+            return (mAppOps.checkOpNoThrow(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg)
+                    == AppOpsManager.MODE_ALLOWED);
+        }
+
+        /**
+         * System-only API for getting a list of current (i.e. not cleared) notifications.
+         *
+         * Requires ACCESS_NOTIFICATIONS which is signature|system.
+         */
+        @Override
+        public StatusBarNotification[] getActiveNotifications(String callingPkg) {
+            // enforce() will ensure the calling uid has the correct permission
+            getContext().enforceCallingOrSelfPermission(
+                    android.Manifest.permission.ACCESS_NOTIFICATIONS,
+                    "NotificationManagerService.getActiveNotifications");
+
+            StatusBarNotification[] tmp = null;
+            int uid = Binder.getCallingUid();
+
+            // noteOp will check to make sure the callingPkg matches the uid
+            if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
+                    == AppOpsManager.MODE_ALLOWED) {
+                synchronized (mNotificationList) {
+                    tmp = new StatusBarNotification[mNotificationList.size()];
+                    final int N = mNotificationList.size();
+                    for (int i=0; i<N; i++) {
+                        tmp[i] = mNotificationList.get(i).sbn;
+                    }
+                }
+            }
+            return tmp;
+        }
+
+        /**
+         * System-only API for getting a list of recent (cleared, no longer shown) notifications.
+         *
+         * Requires ACCESS_NOTIFICATIONS which is signature|system.
+         */
+        @Override
+        public StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count) {
+            // enforce() will ensure the calling uid has the correct permission
+            getContext().enforceCallingOrSelfPermission(
+                    android.Manifest.permission.ACCESS_NOTIFICATIONS,
+                    "NotificationManagerService.getHistoricalNotifications");
+
+            StatusBarNotification[] tmp = null;
+            int uid = Binder.getCallingUid();
+
+            // noteOp will check to make sure the callingPkg matches the uid
+            if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
+                    == AppOpsManager.MODE_ALLOWED) {
+                synchronized (mArchive) {
+                    tmp = mArchive.getArray(count);
+                }
+            }
+            return tmp;
+        }
+
+        /**
+         * Register a listener binder directly with the notification manager.
+         *
+         * Only works with system callers. Apps should extend
+         * {@link android.service.notification.NotificationListenerService}.
+         */
+        @Override
+        public void registerListener(final INotificationListener listener,
+                final ComponentName component, final int userid) {
+            checkCallerIsSystem();
+            checkNullListener(listener);
+            registerListenerImpl(listener, component, userid);
+        }
+
+        /**
+         * Remove a listener binder directly
+         */
+        @Override
+        public void unregisterListener(INotificationListener listener, int userid) {
+            checkNullListener(listener);
+            // no need to check permissions; if your listener binder is in the list,
+            // that's proof that you had permission to add it in the first place
+            unregisterListenerImpl(listener, userid);
+        }
+
+        /**
+         * Allow an INotificationListener to simulate a "clear all" operation.
+         *
+         * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onClearAllNotifications}
+         *
+         * @param token The binder for the listener, to check that the caller is allowed
+         */
+        @Override
+        public void cancelNotificationsFromListener(INotificationListener token, String[] keys) {
+            long identity = Binder.clearCallingIdentity();
             try {
-                ToastRecord record;
-                int index = indexOfToastLocked(pkg, callback);
-                // If it's already in the queue, we update it in place, we don't
-                // move it to the end of the queue.
-                if (index >= 0) {
-                    record = mToastQueue.get(index);
-                    record.update(duration);
-                } else {
-                    // Limit the number of toasts that any given package except the android
-                    // package can enqueue.  Prevents DOS attacks and deals with leaks.
-                    if (!isSystemToast) {
-                        int count = 0;
-                        final int N = mToastQueue.size();
-                        for (int i=0; i<N; i++) {
-                             final ToastRecord r = mToastQueue.get(i);
-                             if (r.pkg.equals(pkg)) {
-                                 count++;
-                                 if (count >= MAX_PACKAGE_NOTIFICATIONS) {
-                                     Slog.e(TAG, "Package has already posted " + count
-                                            + " toasts. Not showing more. Package=" + pkg);
-                                     return;
-                                 }
-                             }
+                synchronized (mNotificationList) {
+                    final NotificationListenerInfo info = checkListenerTokenLocked(token);
+                    if (keys != null) {
+                        final int N = keys.length;
+                        for (int i = 0; i < N; i++) {
+                            NotificationRecord r = mNotificationsByKey.get(keys[i]);
+                            if (r != null) {
+                                cancelNotificationFromListenerLocked(info,
+                                        r.sbn.getPackageName(), r.sbn.getTag(), r.sbn.getId());
+                            }
+                        }
+                    } else {
+                        cancelAllLocked(info.userid);
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        private void cancelNotificationFromListenerLocked(NotificationListenerInfo info,
+                String pkg, String tag, int id) {
+            cancelNotification(pkg, tag, id, 0,
+                    Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
+                    true,
+                    info.userid);
+        }
+
+        /**
+         * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
+         *
+         * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
+         *
+         * @param token The binder for the listener, to check that the caller is allowed
+         */
+        @Override
+        public void cancelNotificationFromListener(INotificationListener token, String pkg,
+                String tag, int id) {
+            long identity = Binder.clearCallingIdentity();
+            try {
+                synchronized (mNotificationList) {
+                    final NotificationListenerInfo info = checkListenerTokenLocked(token);
+                    cancelNotificationFromListenerLocked(info,
+                            pkg, tag, id);
+                }
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        /**
+         * Allow an INotificationListener to request the list of outstanding notifications seen by
+         * the current user. Useful when starting up, after which point the listener callbacks
+         * should be used.
+         *
+         * @param token The binder for the listener, to check that the caller is allowed
+         */
+        @Override
+        public StatusBarNotification[] getActiveNotificationsFromListener(
+                INotificationListener token, String[] keys) {
+            synchronized (mNotificationList) {
+                final NotificationListenerInfo info = checkListenerTokenLocked(token);
+                final ArrayList<StatusBarNotification> list
+                        = new ArrayList<StatusBarNotification>();
+                if (keys == null) {
+                    final int N = mNotificationList.size();
+                    for (int i=0; i<N; i++) {
+                        StatusBarNotification sbn = mNotificationList.get(i).sbn;
+                        if (info.enabledAndUserMatches(sbn)) {
+                            list.add(sbn);
                         }
                     }
-
-                    record = new ToastRecord(callingPid, pkg, callback, duration);
-                    mToastQueue.add(record);
-                    index = mToastQueue.size() - 1;
-                    keepProcessAliveLocked(callingPid);
-                }
-                // If it's at index 0, it's the current toast.  It doesn't matter if it's
-                // new or just been updated.  Call back and tell it to show itself.
-                // If the callback fails, this will remove it from the list, so don't
-                // assume that it's valid after this.
-                if (index == 0) {
-                    showNextToastLocked();
-                }
-            } finally {
-                Binder.restoreCallingIdentity(callingId);
-            }
-        }
-    }
-
-    public void cancelToast(String pkg, ITransientNotification callback) {
-        Slog.i(TAG, "cancelToast pkg=" + pkg + " callback=" + callback);
-
-        if (pkg == null || callback == null) {
-            Slog.e(TAG, "Not cancelling notification. pkg=" + pkg + " callback=" + callback);
-            return ;
-        }
-
-        synchronized (mToastQueue) {
-            long callingId = Binder.clearCallingIdentity();
-            try {
-                int index = indexOfToastLocked(pkg, callback);
-                if (index >= 0) {
-                    cancelToastLocked(index);
                 } else {
-                    Slog.w(TAG, "Toast already cancelled. pkg=" + pkg + " callback=" + callback);
+                    final int N = keys.length;
+                    for (int i=0; i<N; i++) {
+                        NotificationRecord r = mNotificationsByKey.get(keys[i]);
+                        if (r != null && info.enabledAndUserMatches(r.sbn)) {
+                            list.add(r.sbn);
+                        }
+                    }
                 }
-            } finally {
-                Binder.restoreCallingIdentity(callingId);
+                return list.toArray(new StatusBarNotification[list.size()]);
             }
         }
-    }
 
-    private void showNextToastLocked() {
-        ToastRecord record = mToastQueue.get(0);
-        while (record != null) {
-            if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback);
-            try {
-                record.callback.show();
-                scheduleTimeoutLocked(record);
-                return;
-            } catch (RemoteException e) {
-                Slog.w(TAG, "Object died trying to show notification " + record.callback
-                        + " in package " + record.pkg);
-                // remove it from the list and let the process die
-                int index = mToastQueue.indexOf(record);
-                if (index >= 0) {
-                    mToastQueue.remove(index);
-                }
-                keepProcessAliveLocked(record.pid);
-                if (mToastQueue.size() > 0) {
-                    record = mToastQueue.get(0);
-                } else {
-                    record = null;
-                }
-            }
-        }
-    }
-
-    private void cancelToastLocked(int index) {
-        ToastRecord record = mToastQueue.get(index);
-        try {
-            record.callback.hide();
-        } catch (RemoteException e) {
-            Slog.w(TAG, "Object died trying to hide notification " + record.callback
-                    + " in package " + record.pkg);
-            // don't worry about this, we're about to remove it from
-            // the list anyway
-        }
-        mToastQueue.remove(index);
-        keepProcessAliveLocked(record.pid);
-        if (mToastQueue.size() > 0) {
-            // Show the next one. If the callback fails, this will remove
-            // it from the list, so don't assume that the list hasn't changed
-            // after this point.
-            showNextToastLocked();
-        }
-    }
-
-    private void scheduleTimeoutLocked(ToastRecord r)
-    {
-        mHandler.removeCallbacksAndMessages(r);
-        Message m = Message.obtain(mHandler, MESSAGE_TIMEOUT, r);
-        long delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY;
-        mHandler.sendMessageDelayed(m, delay);
-    }
-
-    private void handleTimeout(ToastRecord record)
-    {
-        if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " callback=" + record.callback);
-        synchronized (mToastQueue) {
-            int index = indexOfToastLocked(record.pkg, record.callback);
-            if (index >= 0) {
-                cancelToastLocked(index);
-            }
-        }
-    }
-
-    // lock on mToastQueue
-    private int indexOfToastLocked(String pkg, ITransientNotification callback)
-    {
-        IBinder cbak = callback.asBinder();
-        ArrayList<ToastRecord> list = mToastQueue;
-        int len = list.size();
-        for (int i=0; i<len; i++) {
-            ToastRecord r = list.get(i);
-            if (r.pkg.equals(pkg) && r.callback.asBinder() == cbak) {
-                return i;
-            }
-        }
-        return -1;
-    }
-
-    // lock on mToastQueue
-    private void keepProcessAliveLocked(int pid)
-    {
-        int toastCount = 0; // toasts from this pid
-        ArrayList<ToastRecord> list = mToastQueue;
-        int N = list.size();
-        for (int i=0; i<N; i++) {
-            ToastRecord r = list.get(i);
-            if (r.pid == pid) {
-                toastCount++;
-            }
-        }
-        try {
-            mAm.setProcessForeground(mForegroundToken, pid, toastCount > 0);
-        } catch (RemoteException e) {
-            // Shouldn't happen.
-        }
-    }
-
-    private final class WorkerHandler extends Handler
-    {
         @Override
-        public void handleMessage(Message msg)
-        {
-            switch (msg.what)
-            {
-                case MESSAGE_TIMEOUT:
-                    handleTimeout((ToastRecord)msg.obj);
-                    break;
+        public String[] getActiveNotificationKeysFromListener(INotificationListener token) {
+            return NotificationManagerService.this.getActiveNotificationKeysFromListener(token);
+        }
+
+        @Override
+        protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+            if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+                    != PackageManager.PERMISSION_GRANTED) {
+                pw.println("Permission Denial: can't dump NotificationManager from from pid="
+                        + Binder.getCallingPid()
+                        + ", uid=" + Binder.getCallingUid());
+                return;
             }
+
+            dumpImpl(pw);
+        }
+    };
+
+    private String[] getActiveNotificationKeysFromListener(INotificationListener token) {
+        synchronized (mNotificationList) {
+            final NotificationListenerInfo info = checkListenerTokenLocked(token);
+            final ArrayList<String> keys = new ArrayList<String>();
+            final int N = mNotificationList.size();
+            for (int i=0; i<N; i++) {
+                final StatusBarNotification sbn = mNotificationList.get(i).sbn;
+                if (info.enabledAndUserMatches(sbn)) {
+                    keys.add(sbn.getKey());
+                }
+            }
+            return keys.toArray(new String[keys.size()]);
         }
     }
 
+    void dumpImpl(PrintWriter pw) {
+        pw.println("Current Notification Manager state:");
 
-    // Notifications
-    // ============================================================================
-    public void enqueueNotificationWithTag(String pkg, String basePkg, String tag, int id,
-            Notification notification, int[] idOut, int userId)
-    {
-        enqueueNotificationInternal(pkg, basePkg, Binder.getCallingUid(), Binder.getCallingPid(),
-                tag, id, notification, idOut, userId);
-    }
-    
-    private final static int clamp(int x, int low, int high) {
-        return (x < low) ? low : ((x > high) ? high : x);
+        pw.println("  Listeners (" + mEnabledListenersForCurrentUser.size()
+                + ") enabled for current user:");
+        for (ComponentName cmpt : mEnabledListenersForCurrentUser) {
+            pw.println("    " + cmpt);
+        }
+
+        pw.println("  Live listeners (" + mListeners.size() + "):");
+        for (NotificationListenerInfo info : mListeners) {
+            pw.println("    " + info.component
+                    + " (user " + info.userid + "): " + info.listener
+                    + (info.isSystem?" SYSTEM":""));
+        }
+
+        int N;
+
+        synchronized (mToastQueue) {
+            N = mToastQueue.size();
+            if (N > 0) {
+                pw.println("  Toast Queue:");
+                for (int i=0; i<N; i++) {
+                    mToastQueue.get(i).dump(pw, "    ");
+                }
+                pw.println("  ");
+            }
+
+        }
+
+        synchronized (mNotificationList) {
+            N = mNotificationList.size();
+            if (N > 0) {
+                pw.println("  Notification List:");
+                for (int i=0; i<N; i++) {
+                    mNotificationList.get(i).dump(pw, "    ", getContext());
+                }
+                pw.println("  ");
+            }
+
+            N = mLights.size();
+            if (N > 0) {
+                pw.println("  Lights List:");
+                for (int i=0; i<N; i++) {
+                    pw.println("    " + mLights.get(i));
+                }
+                pw.println("  ");
+            }
+
+            pw.println("  mSoundNotification=" + mSoundNotification);
+            pw.println("  mVibrateNotification=" + mVibrateNotification);
+            pw.println("  mDisabledNotifications=0x"
+                    + Integer.toHexString(mDisabledNotifications));
+            pw.println("  mSystemReady=" + mSystemReady);
+            pw.println("  mArchive=" + mArchive.toString());
+            Iterator<StatusBarNotification> iter = mArchive.descendingIterator();
+            int i=0;
+            while (iter.hasNext()) {
+                pw.println("    " + iter.next());
+                if (++i >= 5) {
+                    if (iter.hasNext()) pw.println("    ...");
+                    break;
+                }
+            }
+
+        }
     }
 
-    // Not exposed via Binder; for system use only (otherwise malicious apps could spoof the
-    // uid/pid of another application)
+    /**
+     * The private API only accessible to the system process.
+     */
+    private final NotificationManagerInternal mInternalService = new NotificationManagerInternal() {
+        @Override
+        public void enqueueNotification(String pkg, String basePkg, int callingUid, int callingPid,
+                String tag, int id, Notification notification, int[] idReceived, int userId) {
+            enqueueNotificationInternal(pkg, basePkg, callingUid, callingPid, tag, id, notification,
+                    idReceived, userId);
+        }
+    };
 
-    public void enqueueNotificationInternal(final String pkg, String basePkg, final int callingUid,
+    void enqueueNotificationInternal(final String pkg, String basePkg, final int callingUid,
             final int callingPid, final String tag, final int id, final Notification notification,
-            int[] idOut, int incomingUserId)
-    {
+            int[] idOut, int incomingUserId) {
         if (DBG) {
-            Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id + " notification=" + notification);
+            Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id
+                    + " notification=" + notification);
         }
         checkCallerIsSystemOrSameApp(pkg);
         final boolean isSystemNotification = isUidSystem(callingUid) || ("android".equals(pkg));
@@ -1779,6 +1858,10 @@
                                 old.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE;
                         }
                     }
+                    if (old != null) {
+                        mNotificationsByKey.remove(old.sbn.getKey());
+                    }
+                    mNotificationsByKey.put(n.getKey(), r);
 
                     // Ensure if this is a foreground service that the proper additional
                     // flags are set.
@@ -1798,23 +1881,21 @@
                     if (notification.icon != 0) {
                         if (old != null && old.statusBarKey != null) {
                             r.statusBarKey = old.statusBarKey;
-                            long identity = Binder.clearCallingIdentity();
+                            final long identity = Binder.clearCallingIdentity();
                             try {
                                 mStatusBar.updateNotification(r.statusBarKey, n);
-                            }
-                            finally {
+                            } finally {
                                 Binder.restoreCallingIdentity(identity);
                             }
                         } else {
-                            long identity = Binder.clearCallingIdentity();
+                            final long identity = Binder.clearCallingIdentity();
                             try {
                                 r.statusBarKey = mStatusBar.addNotification(n);
                                 if ((n.getNotification().flags & Notification.FLAG_SHOW_LIGHTS) != 0
                                         && canInterrupt) {
                                     mAttentionLight.pulse();
                                 }
-                            }
-                            finally {
+                            } finally {
                                 Binder.restoreCallingIdentity(identity);
                             }
                         }
@@ -1827,33 +1908,32 @@
                     } else {
                         Slog.e(TAG, "Not posting notification with icon==0: " + notification);
                         if (old != null && old.statusBarKey != null) {
-                            long identity = Binder.clearCallingIdentity();
+                            final long identity = Binder.clearCallingIdentity();
                             try {
                                 mStatusBar.removeNotification(old.statusBarKey);
-                            }
-                            finally {
+                            } finally {
                                 Binder.restoreCallingIdentity(identity);
                             }
 
                             notifyRemovedLocked(r);
                         }
                         // ATTENTION: in a future release we will bail out here
-                        // so that we do not play sounds, show lights, etc. for invalid notifications
+                        // so that we do not play sounds, show lights, etc. for invalid
+                        // notifications
                         Slog.e(TAG, "WARNING: In a future release this will crash the app: "
                                 + n.getPackageName());
                     }
 
                     // If we're not supposed to beep, vibrate, etc. then don't.
-                    if (((mDisabledNotifications & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) == 0)
+                    if (((mDisabledNotifications
+                            & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) == 0)
                             && (!(old != null
                                 && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0 ))
                             && (r.getUserId() == UserHandle.USER_ALL ||
                                 (r.getUserId() == userId && r.getUserId() == currentUser))
                             && canInterrupt
-                            && mSystemReady) {
-
-                        final AudioManager audioManager = (AudioManager) mContext
-                        .getSystemService(Context.AUDIO_SERVICE);
+                            && mSystemReady
+                            && mAudioManager != null) {
 
                         // sound
 
@@ -1872,7 +1952,7 @@
                             soundUri = Settings.System.DEFAULT_NOTIFICATION_URI;
 
                             // check to see if the default notification sound is silent
-                            ContentResolver resolver = mContext.getContentResolver();
+                            ContentResolver resolver = getContext().getContentResolver();
                             hasValidSound = Settings.System.getString(resolver,
                                    Settings.System.NOTIFICATION_SOUND) != null;
                         } else if (notification.sound != null) {
@@ -1881,7 +1961,8 @@
                         }
 
                         if (hasValidSound) {
-                            boolean looping = (notification.flags & Notification.FLAG_INSISTENT) != 0;
+                            boolean looping =
+                                    (notification.flags & Notification.FLAG_INSISTENT) != 0;
                             int audioStreamType;
                             if (notification.audioStreamType >= 0) {
                                 audioStreamType = notification.audioStreamType;
@@ -1891,11 +1972,12 @@
                             mSoundNotification = r;
                             // do not play notifications if stream volume is 0 (typically because
                             // ringer mode is silent) or if there is a user of exclusive audio focus
-                            if ((audioManager.getStreamVolume(audioStreamType) != 0)
-                                    && !audioManager.isAudioFocusExclusive()) {
+                            if ((mAudioManager.getStreamVolume(audioStreamType) != 0)
+                                    && !mAudioManager.isAudioFocusExclusive()) {
                                 final long identity = Binder.clearCallingIdentity();
                                 try {
-                                    final IRingtonePlayer player = mAudioService.getRingtonePlayer();
+                                    final IRingtonePlayer player =
+                                            mAudioManager.getRingtonePlayer();
                                     if (player != null) {
                                         player.playAsync(soundUri, user, looping, audioStreamType);
                                     }
@@ -1915,7 +1997,7 @@
                         final boolean convertSoundToVibration =
                                    !hasCustomVibrate
                                 && hasValidSound
-                                && (audioManager.getRingerMode()
+                                && (mAudioManager.getRingerMode()
                                            == AudioManager.RINGER_MODE_VIBRATE);
 
                         // The DEFAULT_VIBRATE flag trumps any custom vibration AND the fallback.
@@ -1923,7 +2005,7 @@
                                 (notification.defaults & Notification.DEFAULT_VIBRATE) != 0;
 
                         if ((useDefaultVibrate || convertSoundToVibration || hasCustomVibrate)
-                                && !(audioManager.getRingerMode()
+                                && !(mAudioManager.getRingerMode()
                                         == AudioManager.RINGER_MODE_SILENT)) {
                             mVibrateNotification = r;
 
@@ -1977,8 +2059,173 @@
         idOut[0] = id;
     }
 
-    private void sendAccessibilityEvent(Notification notification, CharSequence packageName) {
-        AccessibilityManager manager = AccessibilityManager.getInstance(mContext);
+     void registerListenerImpl(final INotificationListener listener,
+            final ComponentName component, final int userid) {
+        synchronized (mNotificationList) {
+            try {
+                NotificationListenerInfo info
+                        = new NotificationListenerInfo(listener, component, userid, true);
+                listener.asBinder().linkToDeath(info, 0);
+                mListeners.add(info);
+            } catch (RemoteException e) {
+                // already dead
+            }
+        }
+    }
+
+    /**
+     * Removes a listener from the list and unbinds from its service.
+     */
+    void unregisterListenerImpl(final INotificationListener listener, final int userid) {
+        NotificationListenerInfo info = removeListenerImpl(listener, userid);
+        if (info != null && info.connection != null) {
+            getContext().unbindService(info.connection);
+        }
+    }
+
+    /**
+     * Removes a listener from the list but does not unbind from the listener's service.
+     *
+     * @return the removed listener.
+     */
+    NotificationListenerInfo removeListenerImpl(
+            final INotificationListener listener, final int userid) {
+        NotificationListenerInfo listenerInfo = null;
+        synchronized (mNotificationList) {
+            final int N = mListeners.size();
+            for (int i=N-1; i>=0; i--) {
+                final NotificationListenerInfo info = mListeners.get(i);
+                if (info.listener.asBinder() == listener.asBinder()
+                        && info.userid == userid) {
+                    listenerInfo = mListeners.remove(i);
+                }
+            }
+        }
+        return listenerInfo;
+    }
+
+    void showNextToastLocked() {
+        ToastRecord record = mToastQueue.get(0);
+        while (record != null) {
+            if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback);
+            try {
+                record.callback.show();
+                scheduleTimeoutLocked(record);
+                return;
+            } catch (RemoteException e) {
+                Slog.w(TAG, "Object died trying to show notification " + record.callback
+                        + " in package " + record.pkg);
+                // remove it from the list and let the process die
+                int index = mToastQueue.indexOf(record);
+                if (index >= 0) {
+                    mToastQueue.remove(index);
+                }
+                keepProcessAliveLocked(record.pid);
+                if (mToastQueue.size() > 0) {
+                    record = mToastQueue.get(0);
+                } else {
+                    record = null;
+                }
+            }
+        }
+    }
+
+    void cancelToastLocked(int index) {
+        ToastRecord record = mToastQueue.get(index);
+        try {
+            record.callback.hide();
+        } catch (RemoteException e) {
+            Slog.w(TAG, "Object died trying to hide notification " + record.callback
+                    + " in package " + record.pkg);
+            // don't worry about this, we're about to remove it from
+            // the list anyway
+        }
+        mToastQueue.remove(index);
+        keepProcessAliveLocked(record.pid);
+        if (mToastQueue.size() > 0) {
+            // Show the next one. If the callback fails, this will remove
+            // it from the list, so don't assume that the list hasn't changed
+            // after this point.
+            showNextToastLocked();
+        }
+    }
+
+    private void scheduleTimeoutLocked(ToastRecord r)
+    {
+        mHandler.removeCallbacksAndMessages(r);
+        Message m = Message.obtain(mHandler, MESSAGE_TIMEOUT, r);
+        long delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY;
+        mHandler.sendMessageDelayed(m, delay);
+    }
+
+    private void handleTimeout(ToastRecord record)
+    {
+        if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " callback=" + record.callback);
+        synchronized (mToastQueue) {
+            int index = indexOfToastLocked(record.pkg, record.callback);
+            if (index >= 0) {
+                cancelToastLocked(index);
+            }
+        }
+    }
+
+    // lock on mToastQueue
+    int indexOfToastLocked(String pkg, ITransientNotification callback)
+    {
+        IBinder cbak = callback.asBinder();
+        ArrayList<ToastRecord> list = mToastQueue;
+        int len = list.size();
+        for (int i=0; i<len; i++) {
+            ToastRecord r = list.get(i);
+            if (r.pkg.equals(pkg) && r.callback.asBinder() == cbak) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    // lock on mToastQueue
+    void keepProcessAliveLocked(int pid)
+    {
+        int toastCount = 0; // toasts from this pid
+        ArrayList<ToastRecord> list = mToastQueue;
+        int N = list.size();
+        for (int i=0; i<N; i++) {
+            ToastRecord r = list.get(i);
+            if (r.pid == pid) {
+                toastCount++;
+            }
+        }
+        try {
+            mAm.setProcessForeground(mForegroundToken, pid, toastCount > 0);
+        } catch (RemoteException e) {
+            // Shouldn't happen.
+        }
+    }
+
+    private final class WorkerHandler extends Handler
+    {
+        @Override
+        public void handleMessage(Message msg)
+        {
+            switch (msg.what)
+            {
+                case MESSAGE_TIMEOUT:
+                    handleTimeout((ToastRecord)msg.obj);
+                    break;
+            }
+        }
+    }
+
+
+    // Notifications
+    // ============================================================================
+    static int clamp(int x, int low, int high) {
+        return (x < low) ? low : ((x > high) ? high : x);
+    }
+
+    void sendAccessibilityEvent(Notification notification, CharSequence packageName) {
+        AccessibilityManager manager = AccessibilityManager.getInstance(getContext());
         if (!manager.isEnabled()) {
             return;
         }
@@ -2012,11 +2259,10 @@
 
         // status bar
         if (r.getNotification().icon != 0) {
-            long identity = Binder.clearCallingIdentity();
+            final long identity = Binder.clearCallingIdentity();
             try {
                 mStatusBar.removeNotification(r.statusBarKey);
-            }
-            finally {
+            } finally {
                 Binder.restoreCallingIdentity(identity);
             }
             r.statusBarKey = null;
@@ -2028,7 +2274,7 @@
             mSoundNotification = null;
             final long identity = Binder.clearCallingIdentity();
             try {
-                final IRingtonePlayer player = mAudioService.getRingtonePlayer();
+                final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
                 if (player != null) {
                     player.stopAsync();
                 }
@@ -2064,7 +2310,7 @@
      * Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
      * and none of the {@code mustNotHaveFlags}.
      */
-    private void cancelNotification(final String pkg, final String tag, final int id,
+    void cancelNotification(final String pkg, final String tag, final int id,
             final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
             final int userId) {
         // In enqueueNotificationInternal notifications are added by scheduling the
@@ -2090,6 +2336,7 @@
                         }
 
                         mNotificationList.remove(index);
+                        mNotificationsByKey.remove(r.sbn.getKey());
 
                         cancelNotificationLocked(r, sendDelete);
                         updateLightsLocked();
@@ -2148,6 +2395,7 @@
                     return true;
                 }
                 mNotificationList.remove(i);
+                mNotificationsByKey.remove(r.sbn.getKey());
                 cancelNotificationLocked(r, false);
             }
             if (canceledSomething) {
@@ -2157,26 +2405,7 @@
         }
     }
 
-    public void cancelNotificationWithTag(String pkg, String tag, int id, int userId) {
-        checkCallerIsSystemOrSameApp(pkg);
-        userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
-                Binder.getCallingUid(), userId, true, false, "cancelNotificationWithTag", pkg);
-        // Don't allow client applications to cancel foreground service notis.
-        cancelNotification(pkg, tag, id, 0,
-                Binder.getCallingUid() == Process.SYSTEM_UID
-                ? 0 : Notification.FLAG_FOREGROUND_SERVICE, false, userId);
-    }
 
-    public void cancelAllNotifications(String pkg, int userId) {
-        checkCallerIsSystemOrSameApp(pkg);
-
-        userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
-                Binder.getCallingUid(), userId, true, false, "cancelAllNotifications", pkg);
-
-        // Calling from user space, don't allow the canceling of actively
-        // running foreground services.
-        cancelAllNotificationsInt(pkg, 0, Notification.FLAG_FOREGROUND_SERVICE, true, userId);
-    }
 
     // Return true if the UID is a system or phone UID and therefore should not have
     // any notifications or toasts blocked.
@@ -2214,29 +2443,28 @@
         }
     }
 
-    void cancelAll(int userId) {
-        synchronized (mNotificationList) {
-            final int N = mNotificationList.size();
-            for (int i=N-1; i>=0; i--) {
-                NotificationRecord r = mNotificationList.get(i);
+    void cancelAllLocked(int userId) {
+        final int N = mNotificationList.size();
+        for (int i=N-1; i>=0; i--) {
+            NotificationRecord r = mNotificationList.get(i);
 
-                if (!notificationMatchesUserId(r, userId)) {
-                    continue;
-                }
-
-                if ((r.getFlags() & (Notification.FLAG_ONGOING_EVENT
-                                | Notification.FLAG_NO_CLEAR)) == 0) {
-                    mNotificationList.remove(i);
-                    cancelNotificationLocked(r, true);
-                }
+            if (!notificationMatchesUserId(r, userId)) {
+                continue;
             }
 
-            updateLightsLocked();
+            if ((r.getFlags() & (Notification.FLAG_ONGOING_EVENT
+                            | Notification.FLAG_NO_CLEAR)) == 0) {
+                mNotificationList.remove(i);
+                mNotificationsByKey.remove(r.sbn.getKey());
+                cancelNotificationLocked(r, true);
+            }
         }
+
+        updateLightsLocked();
     }
 
     // lock on mNotificationList
-    private void updateLightsLocked()
+    void updateLightsLocked()
     {
         // handle notification lights
         if (mLedNotification == null) {
@@ -2262,14 +2490,14 @@
             }
             if (mNotificationPulseEnabled) {
                 // pulse repeatedly
-                mNotificationLight.setFlashing(ledARGB, LightsService.LIGHT_FLASH_TIMED,
+                mNotificationLight.setFlashing(ledARGB, Light.LIGHT_FLASH_TIMED,
                         ledOnMS, ledOffMS);
             }
         }
     }
 
     // lock on mNotificationList
-    private int indexOfNotificationLocked(String pkg, String tag, int id, int userId)
+    int indexOfNotificationLocked(String pkg, String tag, int id, int userId)
     {
         ArrayList<NotificationRecord> list = mNotificationList;
         final int len = list.size();
@@ -2299,81 +2527,4 @@
             updateLightsLocked();
         }
     }
-
-    // ======================================================================
-    @Override
-    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
-                != PackageManager.PERMISSION_GRANTED) {
-            pw.println("Permission Denial: can't dump NotificationManager from from pid="
-                    + Binder.getCallingPid()
-                    + ", uid=" + Binder.getCallingUid());
-            return;
-        }
-
-        pw.println("Current Notification Manager state:");
-
-        pw.println("  Listeners (" + mEnabledListenersForCurrentUser.size()
-                + ") enabled for current user:");
-        for (ComponentName cmpt : mEnabledListenersForCurrentUser) {
-            pw.println("    " + cmpt);
-        }
-
-        pw.println("  Live listeners (" + mListeners.size() + "):");
-        for (NotificationListenerInfo info : mListeners) {
-            pw.println("    " + info.component
-                    + " (user " + info.userid + "): " + info.listener
-                    + (info.isSystem?" SYSTEM":""));
-        }
-
-        int N;
-
-        synchronized (mToastQueue) {
-            N = mToastQueue.size();
-            if (N > 0) {
-                pw.println("  Toast Queue:");
-                for (int i=0; i<N; i++) {
-                    mToastQueue.get(i).dump(pw, "    ");
-                }
-                pw.println("  ");
-            }
-
-        }
-
-        synchronized (mNotificationList) {
-            N = mNotificationList.size();
-            if (N > 0) {
-                pw.println("  Notification List:");
-                for (int i=0; i<N; i++) {
-                    mNotificationList.get(i).dump(pw, "    ", mContext);
-                }
-                pw.println("  ");
-            }
-
-            N = mLights.size();
-            if (N > 0) {
-                pw.println("  Lights List:");
-                for (int i=0; i<N; i++) {
-                    pw.println("    " + mLights.get(i));
-                }
-                pw.println("  ");
-            }
-
-            pw.println("  mSoundNotification=" + mSoundNotification);
-            pw.println("  mVibrateNotification=" + mVibrateNotification);
-            pw.println("  mDisabledNotifications=0x" + Integer.toHexString(mDisabledNotifications));
-            pw.println("  mSystemReady=" + mSystemReady);
-            pw.println("  mArchive=" + mArchive.toString());
-            Iterator<StatusBarNotification> iter = mArchive.descendingIterator();
-            int i=0;
-            while (iter.hasNext()) {
-                pw.println("    " + iter.next());
-                if (++i >= 5) {
-                    if (iter.hasNext()) pw.println("    ...");
-                    break;
-                }
-            }
-
-        }
-    }
 }
diff --git a/services/java/com/android/server/os/SchedulingPolicyService.java b/services/core/java/com/android/server/os/SchedulingPolicyService.java
similarity index 100%
rename from services/java/com/android/server/os/SchedulingPolicyService.java
rename to services/core/java/com/android/server/os/SchedulingPolicyService.java
diff --git a/services/java/com/android/server/pm/BasePermission.java b/services/core/java/com/android/server/pm/BasePermission.java
similarity index 100%
rename from services/java/com/android/server/pm/BasePermission.java
rename to services/core/java/com/android/server/pm/BasePermission.java
diff --git a/services/java/com/android/server/pm/GrantedPermissions.java b/services/core/java/com/android/server/pm/GrantedPermissions.java
similarity index 100%
rename from services/java/com/android/server/pm/GrantedPermissions.java
rename to services/core/java/com/android/server/pm/GrantedPermissions.java
diff --git a/services/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
similarity index 97%
rename from services/java/com/android/server/pm/Installer.java
rename to services/core/java/com/android/server/pm/Installer.java
index b776ce1..82d3f53 100644
--- a/services/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -16,6 +16,9 @@
 
 package com.android.server.pm;
 
+import com.android.server.SystemService;
+
+import android.content.Context;
 import android.content.pm.PackageStats;
 import android.net.LocalSocket;
 import android.net.LocalSocketAddress;
@@ -25,21 +28,28 @@
 import java.io.InputStream;
 import java.io.OutputStream;
 
-public final class Installer {
+public final class Installer extends SystemService {
     private static final String TAG = "Installer";
 
     private static final boolean LOCAL_DEBUG = false;
 
     InputStream mIn;
-
     OutputStream mOut;
-
     LocalSocket mSocket;
 
     byte buf[] = new byte[1024];
-
     int buflen = 0;
 
+    public Installer(Context context) {
+        super(context);
+    }
+
+    @Override
+    public void onStart() {
+        Slog.i(TAG, "Waiting for installd to be ready.");
+        ping();
+    }
+
     private boolean connect() {
         if (mSocket != null) {
             return true;
diff --git a/services/java/com/android/server/pm/KeySetManager.java b/services/core/java/com/android/server/pm/KeySetManager.java
similarity index 100%
rename from services/java/com/android/server/pm/KeySetManager.java
rename to services/core/java/com/android/server/pm/KeySetManager.java
diff --git a/services/java/com/android/server/pm/PackageKeySetData.java b/services/core/java/com/android/server/pm/PackageKeySetData.java
similarity index 100%
rename from services/java/com/android/server/pm/PackageKeySetData.java
rename to services/core/java/com/android/server/pm/PackageKeySetData.java
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
similarity index 99%
rename from services/java/com/android/server/pm/PackageManagerService.java
rename to services/core/java/com/android/server/pm/PackageManagerService.java
index f871cb1..2d26851 100755
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -41,10 +41,12 @@
 import com.android.internal.util.FastPrintWriter;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.XmlUtils;
-import com.android.server.DeviceStorageMonitorService;
 import com.android.server.EventLogTags;
 import com.android.server.IntentResolver;
+import com.android.server.LocalServices;
+import com.android.server.ServiceThread;
 import com.android.server.Watchdog;
+import com.android.server.storage.DeviceStorageMonitorInternal;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -95,6 +97,7 @@
 import android.content.pm.VerifierDeviceIdentity;
 import android.content.pm.VerifierInfo;
 import android.content.res.Resources;
+import android.hardware.display.DisplayManager;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Build;
@@ -104,7 +107,6 @@
 import android.os.FileObserver;
 import android.os.FileUtils;
 import android.os.Handler;
-import android.os.HandlerThread;
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
@@ -134,7 +136,6 @@
 import android.util.SparseArray;
 import android.util.Xml;
 import android.view.Display;
-import android.view.WindowManager;
 
 import java.io.BufferedInputStream;
 import java.io.BufferedOutputStream;
@@ -275,13 +276,13 @@
 
     static final String mTempContainerPrefix = "smdl2tmp";
 
+    final ServiceThread mHandlerThread;
+
     private static String sPreferredInstructionSet;
 
     private static final String IDMAP_PREFIX = "/data/resource-cache/";
     private static final String IDMAP_SUFFIX = "@idmap";
 
-    final HandlerThread mHandlerThread = new HandlerThread("PackageManager",
-            Process.THREAD_PRIORITY_BACKGROUND);
     final PackageHandler mHandler;
 
     final int mSdkVersion = Build.VERSION.SDK_INT;
@@ -1236,6 +1237,12 @@
         return res;
     }
 
+    private static void getDefaultDisplayMetrics(Context context, DisplayMetrics metrics) {
+        DisplayManager displayManager = (DisplayManager) context.getSystemService(
+                Context.DISPLAY_SERVICE);
+        displayManager.getDisplay(Display.DEFAULT_DISPLAY).getMetrics(metrics);
+    }
+
     public PackageManagerService(Context context, Installer installer,
             boolean factoryTest, boolean onlyCore) {
         EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START,
@@ -1282,17 +1289,16 @@
 
         mInstaller = installer;
 
-        WindowManager wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
-        Display d = wm.getDefaultDisplay();
-        d.getMetrics(mMetrics);
+        getDefaultDisplayMetrics(context, mMetrics);
 
         synchronized (mInstallLock) {
         // writer
         synchronized (mPackages) {
+            mHandlerThread = new ServiceThread(TAG,
+                    Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
             mHandlerThread.start();
             mHandler = new PackageHandler(mHandlerThread.getLooper());
-            Watchdog.getInstance().addThread(mHandler, mHandlerThread.getName(),
-                    WATCHDOG_TIMEOUT);
+            Watchdog.getInstance().addThread(mHandler, WATCHDOG_TIMEOUT);
 
             File dataDir = Environment.getDataDirectory();
             mAppDataDir = new File(dataDir, "data");
@@ -2790,15 +2796,41 @@
         }
     }
 
+    /**
+     * Compares two sets of signatures. Returns:
+     * <br />
+     * {@link PackageManager#SIGNATURE_NEITHER_SIGNED}: if both signature sets are null,
+     * <br />
+     * {@link PackageManager#SIGNATURE_FIRST_NOT_SIGNED}: if the first signature set is null,
+     * <br />
+     * {@link PackageManager#SIGNATURE_SECOND_NOT_SIGNED}: if the second signature set is null,
+     * <br />
+     * {@link PackageManager#SIGNATURE_MATCH}: if the two signature sets are identical,
+     * <br />
+     * {@link PackageManager#SIGNATURE_NO_MATCH}: if the two signature sets differ.
+     */
     static int compareSignatures(Signature[] s1, Signature[] s2) {
         if (s1 == null) {
             return s2 == null
                     ? PackageManager.SIGNATURE_NEITHER_SIGNED
                     : PackageManager.SIGNATURE_FIRST_NOT_SIGNED;
         }
+
         if (s2 == null) {
             return PackageManager.SIGNATURE_SECOND_NOT_SIGNED;
         }
+
+        if (s1.length != s2.length) {
+            return PackageManager.SIGNATURE_NO_MATCH;
+        }
+
+        // Since both signature sets are of size 1, we can compare without HashSets.
+        if (s1.length == 1) {
+            return s1[0].equals(s2[0]) ?
+                    PackageManager.SIGNATURE_MATCH :
+                    PackageManager.SIGNATURE_NO_MATCH;
+        }
+
         HashSet<Signature> set1 = new HashSet<Signature>();
         for (Signature sig : s1) {
             set1.add(sig);
@@ -8007,6 +8039,15 @@
             return pkgLite.recommendedInstallLocation;
         }
 
+        private long getMemoryLowThreshold() {
+            final DeviceStorageMonitorInternal
+                    dsm = LocalServices.getService(DeviceStorageMonitorInternal.class);
+            if (dsm == null) {
+                return 0L;
+            }
+            return dsm.getMemoryLowThreshold();
+        }
+
         /*
          * Invoke remote method to get package information and install
          * location values. Override install location based on default
@@ -8024,15 +8065,9 @@
                 Slog.w(TAG, "Conflicting flags specified for installing on both internal and external");
                 ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
             } else {
-                final long lowThreshold;
-
-                final DeviceStorageMonitorService dsm = (DeviceStorageMonitorService) ServiceManager
-                        .getService(DeviceStorageMonitorService.SERVICE);
-                if (dsm == null) {
+                final long lowThreshold = getMemoryLowThreshold();
+                if (lowThreshold == 0L) {
                     Log.w(TAG, "Couldn't get low memory threshold; no free limit imposed");
-                    lowThreshold = 0L;
-                } else {
-                    lowThreshold = dsm.getMemoryLowThreshold();
                 }
 
                 try {
@@ -8596,8 +8631,8 @@
         boolean checkFreeStorage(IMediaContainerService imcs) throws RemoteException {
             final long lowThreshold;
 
-            final DeviceStorageMonitorService dsm = (DeviceStorageMonitorService) ServiceManager
-                    .getService(DeviceStorageMonitorService.SERVICE);
+            final DeviceStorageMonitorInternal
+                    dsm = LocalServices.getService(DeviceStorageMonitorInternal.class);
             if (dsm == null) {
                 Log.w(TAG, "Couldn't get low memory threshold; no free limit imposed");
                 lowThreshold = 0L;
@@ -10423,10 +10458,10 @@
                 clearExternalStorageDataSync(packageName, userId, true);
                 if (succeeded) {
                     // invoke DeviceStorageMonitor's update method to clear any notifications
-                    DeviceStorageMonitorService dsm = (DeviceStorageMonitorService)
-                            ServiceManager.getService(DeviceStorageMonitorService.SERVICE);
+                    DeviceStorageMonitorInternal
+                            dsm = LocalServices.getService(DeviceStorageMonitorInternal.class);
                     if (dsm != null) {
-                        dsm.updateMemory();
+                        dsm.checkMemory();
                     }
                 }
                 if(observer != null) {
@@ -12328,9 +12363,13 @@
     public boolean isStorageLow() {
         final long token = Binder.clearCallingIdentity();
         try {
-            final DeviceStorageMonitorService dsm = (DeviceStorageMonitorService) ServiceManager
-                    .getService(DeviceStorageMonitorService.SERVICE);
-            return dsm.isMemoryLow();
+            final DeviceStorageMonitorInternal
+                    dsm = LocalServices.getService(DeviceStorageMonitorInternal.class);
+            if (dsm != null) {
+                return dsm.isMemoryLow();
+            } else {
+                return false;
+            }
         } finally {
             Binder.restoreCallingIdentity(token);
         }
diff --git a/services/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
similarity index 100%
rename from services/java/com/android/server/pm/PackageSetting.java
rename to services/core/java/com/android/server/pm/PackageSetting.java
diff --git a/services/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
similarity index 100%
rename from services/java/com/android/server/pm/PackageSettingBase.java
rename to services/core/java/com/android/server/pm/PackageSettingBase.java
diff --git a/services/java/com/android/server/pm/PackageSignatures.java b/services/core/java/com/android/server/pm/PackageSignatures.java
similarity index 100%
rename from services/java/com/android/server/pm/PackageSignatures.java
rename to services/core/java/com/android/server/pm/PackageSignatures.java
diff --git a/services/java/com/android/server/pm/PackageVerificationResponse.java b/services/core/java/com/android/server/pm/PackageVerificationResponse.java
similarity index 100%
rename from services/java/com/android/server/pm/PackageVerificationResponse.java
rename to services/core/java/com/android/server/pm/PackageVerificationResponse.java
diff --git a/services/java/com/android/server/pm/PackageVerificationState.java b/services/core/java/com/android/server/pm/PackageVerificationState.java
similarity index 100%
rename from services/java/com/android/server/pm/PackageVerificationState.java
rename to services/core/java/com/android/server/pm/PackageVerificationState.java
diff --git a/services/java/com/android/server/pm/PendingPackage.java b/services/core/java/com/android/server/pm/PendingPackage.java
similarity index 100%
rename from services/java/com/android/server/pm/PendingPackage.java
rename to services/core/java/com/android/server/pm/PendingPackage.java
diff --git a/services/java/com/android/server/pm/PreferredActivity.java b/services/core/java/com/android/server/pm/PreferredActivity.java
similarity index 98%
rename from services/java/com/android/server/pm/PreferredActivity.java
rename to services/core/java/com/android/server/pm/PreferredActivity.java
index f93ba2f..8916926 100644
--- a/services/java/com/android/server/pm/PreferredActivity.java
+++ b/services/core/java/com/android/server/pm/PreferredActivity.java
@@ -17,7 +17,6 @@
 package com.android.server.pm;
 
 import com.android.internal.util.XmlUtils;
-import com.android.server.PreferredComponent;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
diff --git a/services/java/com/android/server/PreferredComponent.java b/services/core/java/com/android/server/pm/PreferredComponent.java
similarity index 99%
rename from services/java/com/android/server/PreferredComponent.java
rename to services/core/java/com/android/server/pm/PreferredComponent.java
index a7af252..f437372 100644
--- a/services/java/com/android/server/PreferredComponent.java
+++ b/services/core/java/com/android/server/pm/PreferredComponent.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server;
+package com.android.server.pm;
 
 import com.android.internal.util.XmlUtils;
 
diff --git a/services/java/com/android/server/pm/PreferredIntentResolver.java b/services/core/java/com/android/server/pm/PreferredIntentResolver.java
similarity index 100%
rename from services/java/com/android/server/pm/PreferredIntentResolver.java
rename to services/core/java/com/android/server/pm/PreferredIntentResolver.java
diff --git a/services/java/com/android/server/pm/SELinuxMMAC.java b/services/core/java/com/android/server/pm/SELinuxMMAC.java
similarity index 100%
rename from services/java/com/android/server/pm/SELinuxMMAC.java
rename to services/core/java/com/android/server/pm/SELinuxMMAC.java
diff --git a/services/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
similarity index 100%
rename from services/java/com/android/server/pm/Settings.java
rename to services/core/java/com/android/server/pm/Settings.java
diff --git a/services/java/com/android/server/pm/SharedUserSetting.java b/services/core/java/com/android/server/pm/SharedUserSetting.java
similarity index 100%
rename from services/java/com/android/server/pm/SharedUserSetting.java
rename to services/core/java/com/android/server/pm/SharedUserSetting.java
diff --git a/services/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
similarity index 99%
rename from services/java/com/android/server/pm/UserManagerService.java
rename to services/core/java/com/android/server/pm/UserManagerService.java
index c33134a..557b6a3 100644
--- a/services/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -233,9 +233,7 @@
     }
 
     void systemReady() {
-        final Context context = ActivityThread.systemMain().getSystemContext();
-        mUserPackageMonitor.register(context,
-                null, UserHandle.ALL, false);
+        mUserPackageMonitor.register(mContext, null, UserHandle.ALL, false);
         userForeground(UserHandle.USER_OWNER);
     }
 
diff --git a/services/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java
similarity index 82%
rename from services/java/com/android/server/power/Notifier.java
rename to services/core/java/com/android/server/power/Notifier.java
index 264e2e9..f431b0d 100644
--- a/services/java/com/android/server/power/Notifier.java
+++ b/services/core/java/com/android/server/power/Notifier.java
@@ -16,15 +16,19 @@
 
 package com.android.server.power;
 
+import android.app.ActivityManagerInternal;
 import android.app.AppOpsManager;
+
 import com.android.internal.app.IAppOpsService;
 import com.android.internal.app.IBatteryStats;
 import com.android.server.EventLogTags;
+import com.android.server.LocalServices;
 
 import android.app.ActivityManagerNative;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
+import android.hardware.input.InputManagerInternal;
 import android.media.AudioManager;
 import android.media.Ringtone;
 import android.media.RingtoneManager;
@@ -81,6 +85,8 @@
     private final SuspendBlocker mSuspendBlocker;
     private final ScreenOnBlocker mScreenOnBlocker;
     private final WindowManagerPolicy mPolicy;
+    private final ActivityManagerInternal mActivityManagerInternal;
+    private final InputManagerInternal mInputManagerInternal;
 
     private final NotifierHandler mHandler;
     private final Intent mScreenOnIntent;
@@ -115,6 +121,8 @@
         mSuspendBlocker = suspendBlocker;
         mScreenOnBlocker = screenOnBlocker;
         mPolicy = policy;
+        mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
+        mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
 
         mHandler = new NotifierHandler(looper);
         mScreenOnIntent = new Intent(Intent.ACTION_SCREEN_ON);
@@ -123,6 +131,11 @@
         mScreenOffIntent = new Intent(Intent.ACTION_SCREEN_OFF);
         mScreenOffIntent.addFlags(
                 Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND);
+
+        // Initialize interactive state for battery stats.
+        try {
+            mBatteryStats.noteInteractive(true);
+        } catch (RemoteException ex) { }
     }
 
     /**
@@ -189,120 +202,73 @@
     }
 
     /**
-     * Called when the screen is turned on.
+     * Notifies that the device is changing interactive state.
      */
-    public void onScreenOn() {
+    public void onInteractiveStateChangeStarted(boolean interactive, int reason) {
         if (DEBUG) {
-            Slog.d(TAG, "onScreenOn");
-        }
-
-        try {
-            mBatteryStats.noteScreenOn();
-        } catch (RemoteException ex) {
-            // Ignore
-        }
-    }
-
-    /**
-     * Called when the screen is turned off.
-     */
-    public void onScreenOff() {
-        if (DEBUG) {
-            Slog.d(TAG, "onScreenOff");
-        }
-
-        try {
-            mBatteryStats.noteScreenOff();
-        } catch (RemoteException ex) {
-            // Ignore
-        }
-    }
-
-    /**
-     * Called when the screen changes brightness.
-     */
-    public void onScreenBrightness(int brightness) {
-        if (DEBUG) {
-            Slog.d(TAG, "onScreenBrightness: brightness=" + brightness);
-        }
-
-        try {
-            mBatteryStats.noteScreenBrightness(brightness);
-        } catch (RemoteException ex) {
-            // Ignore
-        }
-    }
-
-    /**
-     * Called when the device is waking up from sleep and the
-     * display is about to be turned on.
-     */
-    public void onWakeUpStarted() {
-        if (DEBUG) {
-            Slog.d(TAG, "onWakeUpStarted");
+            Slog.d(TAG, "onInteractiveChangeStarted: interactive=" + interactive
+                    + ", reason=" + reason);
         }
 
         synchronized (mLock) {
-            if (mActualPowerState != POWER_STATE_AWAKE) {
-                mActualPowerState = POWER_STATE_AWAKE;
-                mPendingWakeUpBroadcast = true;
-                if (!mScreenOnBlockerAcquired) {
-                    mScreenOnBlockerAcquired = true;
-                    mScreenOnBlocker.acquire();
+            if (interactive) {
+                // Waking up...
+                if (mActualPowerState != POWER_STATE_AWAKE) {
+                    mActualPowerState = POWER_STATE_AWAKE;
+                    mPendingWakeUpBroadcast = true;
+                    if (!mScreenOnBlockerAcquired) {
+                        mScreenOnBlockerAcquired = true;
+                        mScreenOnBlocker.acquire();
+                    }
+                    updatePendingBroadcastLocked();
                 }
-                updatePendingBroadcastLocked();
+            } else {
+                // Going to sleep...
+                mLastGoToSleepReason = reason;
             }
         }
-    }
 
-    /**
-     * Called when the device has finished waking up from sleep
-     * and the display has been turned on.
-     */
-    public void onWakeUpFinished() {
-        if (DEBUG) {
-            Slog.d(TAG, "onWakeUpFinished");
+        mInputManagerInternal.setInteractive(interactive);
+
+        if (interactive) {
+            try {
+                mBatteryStats.noteInteractive(true);
+            } catch (RemoteException ex) { }
         }
     }
 
     /**
-     * Called when the device is going to sleep.
+     * Notifies that the device has finished changing interactive state.
      */
-    public void onGoToSleepStarted(int reason) {
+    public void onInteractiveStateChangeFinished(boolean interactive) {
         if (DEBUG) {
-            Slog.d(TAG, "onGoToSleepStarted");
+            Slog.d(TAG, "onInteractiveChangeFinished");
         }
 
         synchronized (mLock) {
-            mLastGoToSleepReason = reason;
-        }
-    }
-
-    /**
-     * Called when the device has finished going to sleep and the
-     * display has been turned off.
-     *
-     * This is a good time to make transitions that we don't want the user to see,
-     * such as bringing the key guard to focus.  There's no guarantee for this,
-     * however because the user could turn the device on again at any time.
-     * Some things may need to be protected by other mechanisms that defer screen on.
-     */
-    public void onGoToSleepFinished() {
-        if (DEBUG) {
-            Slog.d(TAG, "onGoToSleepFinished");
-        }
-
-        synchronized (mLock) {
-            if (mActualPowerState != POWER_STATE_ASLEEP) {
-                mActualPowerState = POWER_STATE_ASLEEP;
-                mPendingGoToSleepBroadcast = true;
-                if (mUserActivityPending) {
-                    mUserActivityPending = false;
-                    mHandler.removeMessages(MSG_USER_ACTIVITY);
+            if (!interactive) {
+                // Finished going to sleep...
+                // This is a good time to make transitions that we don't want the user to see,
+                // such as bringing the key guard to focus.  There's no guarantee for this,
+                // however because the user could turn the device on again at any time.
+                // Some things may need to be protected by other mechanisms that defer screen on.
+                if (mActualPowerState != POWER_STATE_ASLEEP) {
+                    mActualPowerState = POWER_STATE_ASLEEP;
+                    mPendingGoToSleepBroadcast = true;
+                    if (mUserActivityPending) {
+                        mUserActivityPending = false;
+                        mHandler.removeMessages(MSG_USER_ACTIVITY);
+                    }
+                    updatePendingBroadcastLocked();
                 }
-                updatePendingBroadcastLocked();
             }
         }
+
+        if (!interactive) {
+            try {
+                mBatteryStats.noteInteractive(false);
+            } catch (RemoteException ex) { }
+        }
     }
 
     /**
@@ -423,13 +389,8 @@
 
         EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 1, 0, 0, 0);
 
-        mPolicy.screenTurningOn(mScreenOnListener);
-
-        try {
-            ActivityManagerNative.getDefault().wakingUp();
-        } catch (RemoteException e) {
-            // ignore it
-        }
+        mPolicy.wakingUp(mScreenOnListener);
+        mActivityManagerInternal.wakingUp();
 
         if (ActivityManagerNative.isSystemReady()) {
             mContext.sendOrderedBroadcastAsUser(mScreenOnIntent, UserHandle.ALL, null,
@@ -479,12 +440,8 @@
 
         EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 0, why, 0, 0);
 
-        mPolicy.screenTurnedOff(why);
-        try {
-            ActivityManagerNative.getDefault().goingToSleep();
-        } catch (RemoteException e) {
-            // ignore it.
-        }
+        mPolicy.goingToSleep(why);
+        mActivityManagerInternal.goingToSleep();
 
         if (ActivityManagerNative.isSystemReady()) {
             mContext.sendOrderedBroadcastAsUser(mScreenOffIntent, UserHandle.ALL, null,
diff --git a/services/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
similarity index 70%
rename from services/java/com/android/server/power/PowerManagerService.java
rename to services/core/java/com/android/server/power/PowerManagerService.java
index 134718b..7138c3e 100644
--- a/services/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -20,12 +20,11 @@
 import com.android.internal.app.IBatteryStats;
 import com.android.server.BatteryService;
 import com.android.server.EventLogTags;
-import com.android.server.LightsService;
-import com.android.server.TwilightService;
+import com.android.server.LocalServices;
+import com.android.server.ServiceThread;
+import com.android.server.lights.Light;
+import com.android.server.lights.LightsManager;
 import com.android.server.Watchdog;
-import com.android.server.am.ActivityManagerService;
-import com.android.server.display.DisplayManagerService;
-import com.android.server.dreams.DreamManagerService;
 
 import android.Manifest;
 import android.content.BroadcastReceiver;
@@ -38,16 +37,18 @@
 import android.database.ContentObserver;
 import android.hardware.SensorManager;
 import android.hardware.SystemSensorManager;
+import android.hardware.display.DisplayManagerInternal;
+import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest;
 import android.net.Uri;
 import android.os.BatteryManager;
 import android.os.Binder;
 import android.os.Handler;
-import android.os.HandlerThread;
 import android.os.IBinder;
 import android.os.IPowerManager;
 import android.os.Looper;
 import android.os.Message;
 import android.os.PowerManager;
+import android.os.PowerManagerInternal;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.SystemClock;
@@ -56,10 +57,12 @@
 import android.os.UserHandle;
 import android.os.WorkSource;
 import android.provider.Settings;
+import android.service.dreams.DreamManagerInternal;
 import android.util.EventLog;
 import android.util.Log;
 import android.util.Slog;
 import android.util.TimeUtils;
+import android.view.Display;
 import android.view.WindowManagerPolicy;
 
 import java.io.FileDescriptor;
@@ -72,7 +75,7 @@
  * The power manager service is responsible for coordinating power management
  * functions on the device.
  */
-public final class PowerManagerService extends IPowerManager.Stub
+public final class PowerManagerService extends com.android.server.SystemService
         implements Watchdog.Monitor {
     private static final String TAG = "PowerManagerService";
 
@@ -81,7 +84,7 @@
 
     // Message: Sent when a user activity timeout occurs to update the power state.
     private static final int MSG_USER_ACTIVITY_TIMEOUT = 1;
-    // Message: Sent when the device enters or exits a napping or dreaming state.
+    // Message: Sent when the device enters or exits a dreaming or dozing state.
     private static final int MSG_SANDMAN = 2;
     // Message: Sent when the screen on blocker is released.
     private static final int MSG_SCREEN_ON_BLOCKER_RELEASED = 3;
@@ -115,19 +118,21 @@
 
     // Wakefulness: The device is asleep and can only be awoken by a call to wakeUp().
     // The screen should be off or in the process of being turned off by the display controller.
+    // The device typically passes through the dozing state first.
     private static final int WAKEFULNESS_ASLEEP = 0;
     // Wakefulness: The device is fully awake.  It can be put to sleep by a call to goToSleep().
-    // When the user activity timeout expires, the device may start napping or go to sleep.
+    // When the user activity timeout expires, the device may start dreaming or go to sleep.
     private static final int WAKEFULNESS_AWAKE = 1;
-    // Wakefulness: The device is napping.  It is deciding whether to dream or go to sleep
-    // but hasn't gotten around to it yet.  It can be awoken by a call to wakeUp(), which
-    // ends the nap. User activity may brighten the screen but does not end the nap.
-    private static final int WAKEFULNESS_NAPPING = 2;
     // Wakefulness: The device is dreaming.  It can be awoken by a call to wakeUp(),
     // which ends the dream.  The device goes to sleep when goToSleep() is called, when
     // the dream ends or when unplugged.
     // User activity may brighten the screen but does not end the dream.
-    private static final int WAKEFULNESS_DREAMING = 3;
+    private static final int WAKEFULNESS_DREAMING = 2;
+    // Wakefulness: The device is dozing.  It is almost asleep but is allowing a special
+    // low-power "doze" dream to run which keeps the display on but lets the application
+    // processor be suspended.  It can be awoken by a call to wakeUp() which ends the dream.
+    // The device fully goes to sleep if the dream cannot be started or ends on its own.
+    private static final int WAKEFULNESS_DOZING = 3;
 
     // Summarizes the state of all active wakelocks.
     private static final int WAKE_LOCK_CPU = 1 << 0;
@@ -136,6 +141,7 @@
     private static final int WAKE_LOCK_BUTTON_BRIGHT = 1 << 3;
     private static final int WAKE_LOCK_PROXIMITY_SCREEN_OFF = 1 << 4;
     private static final int WAKE_LOCK_STAY_AWAKE = 1 << 5; // only set if already awake
+    private static final int WAKE_LOCK_DOZE = 1 << 6;
 
     // Summarizes the user activity state.
     private static final int USER_ACTIVITY_SCREEN_BRIGHT = 1 << 0;
@@ -162,26 +168,20 @@
     // Poll interval in milliseconds for watching boot animation finished.
     private static final int BOOT_ANIMATION_POLL_INTERVAL = 200;
 
-    // If the battery level drops by this percentage and the user activity timeout
-    // has expired, then assume the device is receiving insufficient current to charge
-    // effectively and terminate the dream.
-    private static final int DREAM_BATTERY_LEVEL_DRAIN_CUTOFF = 5;
-
-    private Context mContext;
-    private LightsService mLightsService;
+    private final Context mContext;
+    private LightsManager mLightsManager;
     private BatteryService mBatteryService;
-    private DisplayManagerService mDisplayManagerService;
+    private DisplayManagerInternal mDisplayManagerInternal;
     private IBatteryStats mBatteryStats;
     private IAppOpsService mAppOps;
-    private HandlerThread mHandlerThread;
+    private ServiceThread mHandlerThread;
     private PowerManagerHandler mHandler;
     private WindowManagerPolicy mPolicy;
     private Notifier mNotifier;
-    private DisplayPowerController mDisplayPowerController;
     private WirelessChargerDetector mWirelessChargerDetector;
     private SettingsObserver mSettingsObserver;
-    private DreamManagerService mDreamManager;
-    private LightsService.Light mAttentionLight;
+    private DreamManagerInternal mDreamManager;
+    private Light mAttentionLight;
 
     private final Object mLock = new Object();
 
@@ -193,6 +193,10 @@
     // This is distinct from the screen power state, which is managed separately.
     private int mWakefulness;
 
+    // True if the sandman has just been summoned for the first time since entering the
+    // dreaming or dozing state.  Indicates whether a new dream should begin.
+    private boolean mSandmanSummoned;
+
     // True if MSG_SANDMAN has been scheduled.
     private boolean mSandmanScheduled;
 
@@ -206,6 +210,10 @@
     // A bitfield that summarizes the state of all active wakelocks.
     private int mWakeLockSummary;
 
+    // True if the device is in an interactive state.
+    private boolean mInteractive;
+    private boolean mInteractiveChanging;
+
     // If true, instructs the display controller to wait for the proximity sensor to
     // go negative before turning the screen on.
     private boolean mRequestWaitForNegativeProximity;
@@ -214,11 +222,6 @@
     private long mLastWakeTime;
     private long mLastSleepTime;
 
-    // True if we need to send a wake up or go to sleep finished notification
-    // when the display is ready.
-    private boolean mSendWakeUpFinishedNotificationWhenReady;
-    private boolean mSendGoToSleepFinishedNotificationWhenReady;
-
     // Timestamp of the last call to user activity.
     private long mLastUserActivityTime;
     private long mLastUserActivityTimeNoChangeLights;
@@ -231,9 +234,6 @@
     // requested because it is updated asynchronously by the display power controller.
     private final DisplayPowerRequest mDisplayPowerRequest = new DisplayPowerRequest();
 
-    // The time the screen was last turned off, in elapsedRealtime() timebase.
-    private long mLastScreenOffEventElapsedRealTime;
-
     // True if the display power state has been fully applied, which means the display
     // is actually on or actually off or whatever was requested.
     private boolean mDisplayReady;
@@ -257,15 +257,20 @@
     // screen is coming up.
     private final ScreenOnBlockerImpl mScreenOnBlocker;
 
-    // The display blanker used to turn the screen on or off.
-    private final DisplayBlankerImpl mDisplayBlanker;
-
     // True if systemReady() has been called.
     private boolean mSystemReady;
 
     // True if boot completed occurred.  We keep the screen on until this happens.
     private boolean mBootCompleted;
 
+    // True if auto-suspend mode is enabled.
+    // Refer to autosuspend.h.
+    private boolean mHalAutoSuspendModeEnabled;
+
+    // True if interactive mode is enabled.
+    // Refer to power.h.
+    private boolean mHalInteractiveModeEnabled;
+
     // True if the device is plugged into a power source.
     private boolean mIsPowered;
 
@@ -283,6 +288,12 @@
     // The current dock state.
     private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
 
+    // True to decouple auto-suspend mode from the display state.
+    private boolean mDecoupleHalAutoSuspendModeFromDisplayConfig;
+
+    // True to decouple interactive mode from the display state.
+    private boolean mDecoupleHalInteractiveModeFromDisplayConfig;
+
     // True if the device should wake up when plugged or unplugged.
     private boolean mWakeUpWhenPluggedOrUnpluggedConfig;
 
@@ -301,6 +312,22 @@
     // Default value for dreams activate-on-dock
     private boolean mDreamsActivatedOnDockByDefaultConfig;
 
+    // True if dreams can run while not plugged in.
+    private boolean mDreamsEnabledOnBatteryConfig;
+
+    // Minimum battery level to allow dreaming when powered.
+    // Use -1 to disable this safety feature.
+    private int mDreamsBatteryLevelMinimumWhenPoweredConfig;
+
+    // Minimum battery level to allow dreaming when not powered.
+    // Use -1 to disable this safety feature.
+    private int mDreamsBatteryLevelMinimumWhenNotPoweredConfig;
+
+    // If the battery level drops by this percentage and the user activity timeout
+    // has expired, then assume the device is receiving insufficient current to charge
+    // effectively and terminate the dream.  Use -1 to disable this safety feature.
+    private int mDreamsBatteryLevelDrainCutoffConfig;
+
     // True if dreams are enabled by the user.
     private boolean mDreamsEnabledSetting;
 
@@ -370,69 +397,71 @@
 
     private native void nativeInit();
 
-    private static native void nativeSetPowerState(boolean screenOn, boolean screenBright);
     private static native void nativeAcquireSuspendBlocker(String name);
     private static native void nativeReleaseSuspendBlocker(String name);
     private static native void nativeSetInteractive(boolean enable);
     private static native void nativeSetAutoSuspend(boolean enable);
 
-    public PowerManagerService() {
+    public PowerManagerService(Context context) {
+        super(context);
+        mContext = context;
         synchronized (mLock) {
             mWakeLockSuspendBlocker = createSuspendBlockerLocked("PowerManagerService.WakeLocks");
             mDisplaySuspendBlocker = createSuspendBlockerLocked("PowerManagerService.Display");
             mDisplaySuspendBlocker.acquire();
             mHoldingDisplaySuspendBlocker = true;
+            mHalAutoSuspendModeEnabled = false;
+            mHalInteractiveModeEnabled = true;
 
             mScreenOnBlocker = new ScreenOnBlockerImpl();
-            mDisplayBlanker = new DisplayBlankerImpl();
             mWakefulness = WAKEFULNESS_AWAKE;
-        }
+            mInteractive = true;
 
-        nativeInit();
-        nativeSetPowerState(true, true);
+            nativeInit();
+            nativeSetAutoSuspend(false);
+            nativeSetInteractive(true);
+        }
+    }
+
+    @Override
+    public void onStart() {
+        publishBinderService(Context.POWER_SERVICE, new BinderService());
+        publishLocalService(PowerManagerInternal.class, new LocalService());
     }
 
     /**
      * Initialize the power manager.
      * Must be called before any other functions within the power manager are called.
      */
-    public void init(Context context, LightsService ls,
-            ActivityManagerService am, BatteryService bs, IBatteryStats bss,
-            IAppOpsService appOps, DisplayManagerService dm) {
-        mContext = context;
-        mLightsService = ls;
+    public void init(LightsManager ls,
+            BatteryService bs, IBatteryStats bss,
+            IAppOpsService appOps) {
+        mLightsManager = ls;
         mBatteryService = bs;
         mBatteryStats = bss;
         mAppOps = appOps;
-        mDisplayManagerService = dm;
-        mHandlerThread = new HandlerThread(TAG);
+        mDisplayManagerInternal = getLocalService(DisplayManagerInternal.class);
+        mHandlerThread = new ServiceThread(TAG,
+                Process.THREAD_PRIORITY_DISPLAY, false /*allowIo*/);
         mHandlerThread.start();
         mHandler = new PowerManagerHandler(mHandlerThread.getLooper());
 
         Watchdog.getInstance().addMonitor(this);
-        Watchdog.getInstance().addThread(mHandler, mHandlerThread.getName());
-
-        // Forcibly turn the screen on at boot so that it is in a known power state.
-        // We do this in init() rather than in the constructor because setting the
-        // screen state requires a call into surface flinger which then needs to call back
-        // into the activity manager to check permissions.  Unfortunately the
-        // activity manager is not running when the constructor is called, so we
-        // have to defer setting the screen state until this point.
-        mDisplayBlanker.unblankAllDisplays();
+        Watchdog.getInstance().addThread(mHandler);
     }
 
-    public void setPolicy(WindowManagerPolicy policy) {
+    void setPolicy(WindowManagerPolicy policy) {
         synchronized (mLock) {
             mPolicy = policy;
         }
     }
 
-    public void systemReady(TwilightService twilight, DreamManagerService dreamManager) {
+    public void systemReady() {
         synchronized (mLock) {
             mSystemReady = true;
-            mDreamManager = dreamManager;
+            mDreamManager = LocalServices.getService(DreamManagerInternal.class);
 
-            PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
+            PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
             mScreenBrightnessSettingMinimum = pm.getMinimumScreenBrightnessSetting();
             mScreenBrightnessSettingMaximum = pm.getMaximumScreenBrightnessSetting();
             mScreenBrightnessSettingDefault = pm.getDefaultScreenBrightnessSetting();
@@ -445,18 +474,15 @@
                     mAppOps, createSuspendBlockerLocked("PowerManagerService.Broadcasts"),
                     mScreenOnBlocker, mPolicy);
 
-            // The display power controller runs on the power manager service's
-            // own handler thread to ensure timely operation.
-            mDisplayPowerController = new DisplayPowerController(mHandler.getLooper(),
-                    mContext, mNotifier, mLightsService, twilight, sensorManager,
-                    mDisplayManagerService, mDisplaySuspendBlocker, mDisplayBlanker,
-                    mDisplayPowerControllerCallbacks, mHandler);
-
             mWirelessChargerDetector = new WirelessChargerDetector(sensorManager,
                     createSuspendBlockerLocked("PowerManagerService.WirelessChargerDetector"),
                     mHandler);
             mSettingsObserver = new SettingsObserver(mHandler);
-            mAttentionLight = mLightsService.getLight(LightsService.LIGHT_ID_ATTENTION);
+            mAttentionLight = mLightsManager.getLight(LightsManager.LIGHT_ID_ATTENTION);
+
+            // Initialize display power management.
+            mDisplayManagerInternal.initPowerManagement(
+                    mDisplayPowerCallbacks, mHandler, sensorManager);
 
             // Register for broadcasts from other components of the system.
             IntentFilter filter = new IntentFilter();
@@ -515,6 +541,10 @@
     private void readConfigurationLocked() {
         final Resources resources = mContext.getResources();
 
+        mDecoupleHalAutoSuspendModeFromDisplayConfig = resources.getBoolean(
+                com.android.internal.R.bool.config_powerDecoupleAutoSuspendModeFromDisplay);
+        mDecoupleHalInteractiveModeFromDisplayConfig = resources.getBoolean(
+                com.android.internal.R.bool.config_powerDecoupleInteractiveModeFromDisplay);
         mWakeUpWhenPluggedOrUnpluggedConfig = resources.getBoolean(
                 com.android.internal.R.bool.config_unplugTurnsOnScreen);
         mSuspendWhenScreenOffDueToProximityConfig = resources.getBoolean(
@@ -527,6 +557,14 @@
                 com.android.internal.R.bool.config_dreamsActivatedOnSleepByDefault);
         mDreamsActivatedOnDockByDefaultConfig = resources.getBoolean(
                 com.android.internal.R.bool.config_dreamsActivatedOnDockByDefault);
+        mDreamsEnabledOnBatteryConfig = resources.getBoolean(
+                com.android.internal.R.bool.config_dreamsEnabledOnBattery);
+        mDreamsBatteryLevelMinimumWhenPoweredConfig = resources.getInteger(
+                com.android.internal.R.integer.config_dreamsBatteryLevelMinimumWhenPowered);
+        mDreamsBatteryLevelMinimumWhenNotPoweredConfig = resources.getInteger(
+                com.android.internal.R.integer.config_dreamsBatteryLevelMinimumWhenNotPowered);
+        mDreamsBatteryLevelDrainCutoffConfig = resources.getInteger(
+                com.android.internal.R.integer.config_dreamsBatteryLevelDrainCutoff);
     }
 
     private void updateSettingsLocked() {
@@ -579,41 +617,6 @@
         updatePowerStateLocked();
     }
 
-    @Override // Binder call
-    public void acquireWakeLockWithUid(IBinder lock, int flags, String tag, String packageName,
-            int uid) {
-        acquireWakeLock(lock, flags, tag, packageName, new WorkSource(uid));
-    }
-
-    @Override // Binder call
-    public void acquireWakeLock(IBinder lock, int flags, String tag, String packageName,
-            WorkSource ws) {
-        if (lock == null) {
-            throw new IllegalArgumentException("lock must not be null");
-        }
-        if (packageName == null) {
-            throw new IllegalArgumentException("packageName must not be null");
-        }
-        PowerManager.validateWakeLockParameters(flags, tag);
-
-        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
-        if (ws != null && ws.size() != 0) {
-            mContext.enforceCallingOrSelfPermission(
-                    android.Manifest.permission.UPDATE_DEVICE_STATS, null);
-        } else {
-            ws = null;
-        }
-
-        final int uid = Binder.getCallingUid();
-        final int pid = Binder.getCallingPid();
-        final long ident = Binder.clearCallingIdentity();
-        try {
-            acquireWakeLockInternal(lock, flags, tag, packageName, ws, uid, pid);
-        } finally {
-            Binder.restoreCallingIdentity(ident);
-        }
-    }
-
     private void acquireWakeLockInternal(IBinder lock, int flags, String tag, String packageName,
             WorkSource ws, int uid, int pid) {
         synchronized (mLock) {
@@ -668,22 +671,6 @@
         }
     }
 
-    @Override // Binder call
-    public void releaseWakeLock(IBinder lock, int flags) {
-        if (lock == null) {
-            throw new IllegalArgumentException("lock must not be null");
-        }
-
-        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
-
-        final long ident = Binder.clearCallingIdentity();
-        try {
-            releaseWakeLockInternal(lock, flags);
-        } finally {
-            Binder.restoreCallingIdentity(ident);
-        }
-    }
-
     private void releaseWakeLockInternal(IBinder lock, int flags) {
         synchronized (mLock) {
             int index = findWakeLockIndexLocked(lock);
@@ -746,43 +733,6 @@
         }
     }
 
-    @Override // Binder call
-    public void updateWakeLockUids(IBinder lock, int[] uids) {
-        WorkSource ws = null;
-
-        if (uids != null) {
-            ws = new WorkSource();
-            // XXX should WorkSource have a way to set uids as an int[] instead of adding them
-            // one at a time?
-            for (int i = 0; i < uids.length; i++) {
-                ws.add(uids[i]);
-            }
-        }
-        updateWakeLockWorkSource(lock, ws);
-    }
-
-    @Override // Binder call
-    public void updateWakeLockWorkSource(IBinder lock, WorkSource ws) {
-        if (lock == null) {
-            throw new IllegalArgumentException("lock must not be null");
-        }
-
-        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
-        if (ws != null && ws.size() != 0) {
-            mContext.enforceCallingOrSelfPermission(
-                    android.Manifest.permission.UPDATE_DEVICE_STATS, null);
-        } else {
-            ws = null;
-        }
-
-        final long ident = Binder.clearCallingIdentity();
-        try {
-            updateWakeLockWorkSourceInternal(lock, ws);
-        } finally {
-            Binder.restoreCallingIdentity(ident);
-        }
-    }
-
     private void updateWakeLockWorkSourceInternal(IBinder lock, WorkSource ws) {
         synchronized (mLock) {
             int index = findWakeLockIndexLocked(lock);
@@ -834,16 +784,6 @@
         }
     }
 
-    @Override // Binder call
-    public boolean isWakeLockLevelSupported(int level) {
-        final long ident = Binder.clearCallingIdentity();
-        try {
-            return isWakeLockLevelSupportedInternal(level);
-        } finally {
-            Binder.restoreCallingIdentity(ident);
-        }
-    }
-
     @SuppressWarnings("deprecation")
     private boolean isWakeLockLevelSupportedInternal(int level) {
         synchronized (mLock) {
@@ -852,10 +792,11 @@
                 case PowerManager.SCREEN_DIM_WAKE_LOCK:
                 case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:
                 case PowerManager.FULL_WAKE_LOCK:
+                case PowerManager.DOZE_WAKE_LOCK:
                     return true;
 
                 case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK:
-                    return mSystemReady && mDisplayPowerController.isProximitySensorAvailable();
+                    return mSystemReady && mDisplayManagerInternal.isProximitySensorAvailable();
 
                 default:
                     return false;
@@ -863,40 +804,6 @@
         }
     }
 
-    @Override // Binder call
-    public void userActivity(long eventTime, int event, int flags) {
-        final long now = SystemClock.uptimeMillis();
-        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER)
-                != PackageManager.PERMISSION_GRANTED) {
-            // Once upon a time applications could call userActivity().
-            // Now we require the DEVICE_POWER permission.  Log a warning and ignore the
-            // request instead of throwing a SecurityException so we don't break old apps.
-            synchronized (mLock) {
-                if (now >= mLastWarningAboutUserActivityPermission + (5 * 60 * 1000)) {
-                    mLastWarningAboutUserActivityPermission = now;
-                    Slog.w(TAG, "Ignoring call to PowerManager.userActivity() because the "
-                            + "caller does not have DEVICE_POWER permission.  "
-                            + "Please fix your app!  "
-                            + " pid=" + Binder.getCallingPid()
-                            + " uid=" + Binder.getCallingUid());
-                }
-            }
-            return;
-        }
-
-        if (eventTime > SystemClock.uptimeMillis()) {
-            throw new IllegalArgumentException("event time must not be in the future");
-        }
-
-        final int uid = Binder.getCallingUid();
-        final long ident = Binder.clearCallingIdentity();
-        try {
-            userActivityInternal(eventTime, event, flags, uid);
-        } finally {
-            Binder.restoreCallingIdentity(ident);
-        }
-    }
-
     // Called from native code.
     private void userActivityFromNative(long eventTime, int event, int flags) {
         userActivityInternal(eventTime, event, flags, Process.SYSTEM_UID);
@@ -918,7 +825,8 @@
         }
 
         if (eventTime < mLastSleepTime || eventTime < mLastWakeTime
-                || mWakefulness == WAKEFULNESS_ASLEEP || !mBootCompleted || !mSystemReady) {
+                || mWakefulness == WAKEFULNESS_ASLEEP || mWakefulness == WAKEFULNESS_DOZING
+                || !mBootCompleted || !mSystemReady) {
             return false;
         }
 
@@ -941,27 +849,6 @@
         return false;
     }
 
-    @Override // Binder call
-    public void wakeUp(long eventTime) {
-        if (eventTime > SystemClock.uptimeMillis()) {
-            throw new IllegalArgumentException("event time must not be in the future");
-        }
-
-        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
-
-        final long ident = Binder.clearCallingIdentity();
-        try {
-            wakeUpInternal(eventTime);
-        } finally {
-            Binder.restoreCallingIdentity(ident);
-        }
-    }
-
-    // Called from native code.
-    private void wakeUpFromNative(long eventTime) {
-        wakeUpInternal(eventTime);
-    }
-
     private void wakeUpInternal(long eventTime) {
         synchronized (mLock) {
             if (wakeUpNoUpdateLocked(eventTime)) {
@@ -983,48 +870,25 @@
         switch (mWakefulness) {
             case WAKEFULNESS_ASLEEP:
                 Slog.i(TAG, "Waking up from sleep...");
-                sendPendingNotificationsLocked();
-                mNotifier.onWakeUpStarted();
-                mSendWakeUpFinishedNotificationWhenReady = true;
                 break;
             case WAKEFULNESS_DREAMING:
                 Slog.i(TAG, "Waking up from dream...");
                 break;
-            case WAKEFULNESS_NAPPING:
-                Slog.i(TAG, "Waking up from nap...");
+            case WAKEFULNESS_DOZING:
+                Slog.i(TAG, "Waking up from dozing...");
                 break;
         }
 
         mLastWakeTime = eventTime;
-        mWakefulness = WAKEFULNESS_AWAKE;
         mDirty |= DIRTY_WAKEFULNESS;
+        mWakefulness = WAKEFULNESS_AWAKE;
+        setInteractiveStateLocked(true, 0);
 
         userActivityNoUpdateLocked(
                 eventTime, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID);
         return true;
     }
 
-    @Override // Binder call
-    public void goToSleep(long eventTime, int reason) {
-        if (eventTime > SystemClock.uptimeMillis()) {
-            throw new IllegalArgumentException("event time must not be in the future");
-        }
-
-        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
-
-        final long ident = Binder.clearCallingIdentity();
-        try {
-            goToSleepInternal(eventTime, reason);
-        } finally {
-            Binder.restoreCallingIdentity(ident);
-        }
-    }
-
-    // Called from native code.
-    private void goToSleepFromNative(long eventTime, int reason) {
-        goToSleepInternal(eventTime, reason);
-    }
-
     private void goToSleepInternal(long eventTime, int reason) {
         synchronized (mLock) {
             if (goToSleepNoUpdateLocked(eventTime, reason)) {
@@ -1033,13 +897,17 @@
         }
     }
 
+    // This method is called goToSleep for historical reasons but we actually start
+    // dozing before really going to sleep.
     @SuppressWarnings("deprecation")
     private boolean goToSleepNoUpdateLocked(long eventTime, int reason) {
         if (DEBUG_SPEW) {
             Slog.d(TAG, "goToSleepNoUpdateLocked: eventTime=" + eventTime + ", reason=" + reason);
         }
 
-        if (eventTime < mLastWakeTime || mWakefulness == WAKEFULNESS_ASLEEP
+        if (eventTime < mLastWakeTime
+                || mWakefulness == WAKEFULNESS_ASLEEP
+                || mWakefulness == WAKEFULNESS_DOZING
                 || !mBootCompleted || !mSystemReady) {
             return false;
         }
@@ -1057,13 +925,11 @@
                 break;
         }
 
-        sendPendingNotificationsLocked();
-        mNotifier.onGoToSleepStarted(reason);
-        mSendGoToSleepFinishedNotificationWhenReady = true;
-
         mLastSleepTime = eventTime;
         mDirty |= DIRTY_WAKEFULNESS;
-        mWakefulness = WAKEFULNESS_ASLEEP;
+        mWakefulness = WAKEFULNESS_DOZING;
+        mSandmanSummoned = true;
+        setInteractiveStateLocked(false, reason);
 
         // Report the number of wake locks that will be cleared by going to sleep.
         int numWakeLocksCleared = 0;
@@ -1082,22 +948,6 @@
         return true;
     }
 
-    @Override // Binder call
-    public void nap(long eventTime) {
-        if (eventTime > SystemClock.uptimeMillis()) {
-            throw new IllegalArgumentException("event time must not be in the future");
-        }
-
-        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
-
-        final long ident = Binder.clearCallingIdentity();
-        try {
-            napInternal(eventTime);
-        } finally {
-            Binder.restoreCallingIdentity(ident);
-        }
-    }
-
     private void napInternal(long eventTime) {
         synchronized (mLock) {
             if (napNoUpdateLocked(eventTime)) {
@@ -1119,10 +969,48 @@
         Slog.i(TAG, "Nap time...");
 
         mDirty |= DIRTY_WAKEFULNESS;
-        mWakefulness = WAKEFULNESS_NAPPING;
+        mWakefulness = WAKEFULNESS_DREAMING;
+        mSandmanSummoned = true;
+        setInteractiveStateLocked(true, 0);
         return true;
     }
 
+    // Done dozing, drop everything and go to sleep.
+    private boolean reallyGoToSleepNoUpdateLocked(long eventTime) {
+        if (DEBUG_SPEW) {
+            Slog.d(TAG, "reallyGoToSleepNoUpdateLocked: eventTime=" + eventTime);
+        }
+
+        if (eventTime < mLastWakeTime || mWakefulness == WAKEFULNESS_ASLEEP
+                || !mBootCompleted || !mSystemReady) {
+            return false;
+        }
+
+        Slog.i(TAG, "Sleeping...");
+
+        mDirty |= DIRTY_WAKEFULNESS;
+        mWakefulness = WAKEFULNESS_ASLEEP;
+        setInteractiveStateLocked(false, PowerManager.GO_TO_SLEEP_REASON_TIMEOUT);
+        return true;
+    }
+
+    private void setInteractiveStateLocked(boolean interactive, int reason) {
+        if (mInteractive != interactive) {
+            finishInteractiveStateChangeLocked();
+
+            mInteractive = interactive;
+            mInteractiveChanging = true;
+            mNotifier.onInteractiveStateChangeStarted(interactive, reason);
+        }
+    }
+
+    private void finishInteractiveStateChangeLocked() {
+        if (mInteractiveChanging) {
+            mNotifier.onInteractiveStateChangeFinished(mInteractive);
+            mInteractiveChanging = false;
+        }
+    }
+
     /**
      * Updates the global power state based on dirty bits recorded in mDirty.
      *
@@ -1166,7 +1054,7 @@
 
         // Phase 3: Send notifications, if needed.
         if (mDisplayReady) {
-            sendPendingNotificationsLocked();
+            finishInteractiveStateChangeLocked();
         }
 
         // Phase 4: Update suspend blocker.
@@ -1175,17 +1063,6 @@
         updateSuspendBlockerLocked();
     }
 
-    private void sendPendingNotificationsLocked() {
-        if (mSendWakeUpFinishedNotificationWhenReady) {
-            mSendWakeUpFinishedNotificationWhenReady = false;
-            mNotifier.onWakeUpFinished();
-        }
-        if (mSendGoToSleepFinishedNotificationWhenReady) {
-            mSendGoToSleepFinishedNotificationWhenReady = false;
-            mNotifier.onGoToSleepFinished();
-        }
-    }
-
     /**
      * Updates the value of mIsPowered.
      * Sets DIRTY_IS_POWERED if a change occurred.
@@ -1198,7 +1075,7 @@
             mPlugType = mBatteryService.getPlugType();
             mBatteryLevel = mBatteryService.getBatteryLevel();
 
-            if (DEBUG) {
+            if (DEBUG_SPEW) {
                 Slog.d(TAG, "updateIsPoweredLocked: wasPowered=" + wasPowered
                         + ", mIsPowered=" + mIsPowered
                         + ", oldPlugType=" + oldPlugType
@@ -1258,8 +1135,7 @@
         }
 
         // If already dreaming and becoming powered, then don't wake.
-        if (mIsPowered && (mWakefulness == WAKEFULNESS_NAPPING
-                || mWakefulness == WAKEFULNESS_DREAMING)) {
+        if (mIsPowered && mWakefulness == WAKEFULNESS_DREAMING) {
             return false;
         }
 
@@ -1306,35 +1182,42 @@
                         mWakeLockSummary |= WAKE_LOCK_CPU;
                         break;
                     case PowerManager.FULL_WAKE_LOCK:
-                        if (mWakefulness != WAKEFULNESS_ASLEEP) {
-                            mWakeLockSummary |= WAKE_LOCK_CPU
-                                    | WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_BUTTON_BRIGHT;
-                            if (mWakefulness == WAKEFULNESS_AWAKE) {
-                                mWakeLockSummary |= WAKE_LOCK_STAY_AWAKE;
-                            }
-                        }
+                        mWakeLockSummary |= WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_BUTTON_BRIGHT;
                         break;
                     case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:
-                        if (mWakefulness != WAKEFULNESS_ASLEEP) {
-                            mWakeLockSummary |= WAKE_LOCK_CPU | WAKE_LOCK_SCREEN_BRIGHT;
-                            if (mWakefulness == WAKEFULNESS_AWAKE) {
-                                mWakeLockSummary |= WAKE_LOCK_STAY_AWAKE;
-                            }
-                        }
+                        mWakeLockSummary |= WAKE_LOCK_SCREEN_BRIGHT;
                         break;
                     case PowerManager.SCREEN_DIM_WAKE_LOCK:
-                        if (mWakefulness != WAKEFULNESS_ASLEEP) {
-                            mWakeLockSummary |= WAKE_LOCK_CPU | WAKE_LOCK_SCREEN_DIM;
-                            if (mWakefulness == WAKEFULNESS_AWAKE) {
-                                mWakeLockSummary |= WAKE_LOCK_STAY_AWAKE;
-                            }
-                        }
+                        mWakeLockSummary |= WAKE_LOCK_SCREEN_DIM;
                         break;
                     case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK:
-                        if (mWakefulness != WAKEFULNESS_ASLEEP) {
-                            mWakeLockSummary |= WAKE_LOCK_PROXIMITY_SCREEN_OFF;
-                        }
+                        mWakeLockSummary |= WAKE_LOCK_PROXIMITY_SCREEN_OFF;
                         break;
+                    case PowerManager.DOZE_WAKE_LOCK:
+                        mWakeLockSummary |= WAKE_LOCK_DOZE;
+                        break;
+                }
+            }
+
+            // Cancel wake locks that make no sense based on the current state.
+            if (mWakefulness != WAKEFULNESS_DOZING) {
+                mWakeLockSummary &= ~WAKE_LOCK_DOZE;
+            }
+            if (mWakefulness == WAKEFULNESS_ASLEEP
+                    || (mWakeLockSummary & WAKE_LOCK_DOZE) != 0) {
+                mWakeLockSummary &= ~(WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_SCREEN_DIM
+                        | WAKE_LOCK_BUTTON_BRIGHT);
+                if (mWakefulness == WAKEFULNESS_ASLEEP) {
+                    mWakeLockSummary &= ~WAKE_LOCK_PROXIMITY_SCREEN_OFF;
+                }
+            }
+
+            // Infer implied wake locks where necessary based on the current state.
+            if ((mWakeLockSummary & (WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_SCREEN_DIM)) != 0) {
+                if (mWakefulness == WAKEFULNESS_AWAKE) {
+                    mWakeLockSummary |= WAKE_LOCK_CPU | WAKE_LOCK_STAY_AWAKE;
+                } else if (mWakefulness == WAKEFULNESS_DREAMING) {
+                    mWakeLockSummary |= WAKE_LOCK_CPU;
                 }
             }
 
@@ -1355,11 +1238,14 @@
      */
     private void updateUserActivitySummaryLocked(long now, int dirty) {
         // Update the status of the user activity timeout timer.
-        if ((dirty & (DIRTY_USER_ACTIVITY | DIRTY_WAKEFULNESS | DIRTY_SETTINGS)) != 0) {
+        if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY
+                | DIRTY_WAKEFULNESS | DIRTY_SETTINGS)) != 0) {
             mHandler.removeMessages(MSG_USER_ACTIVITY_TIMEOUT);
 
             long nextTimeout = 0;
-            if (mWakefulness != WAKEFULNESS_ASLEEP) {
+            if (mWakefulness == WAKEFULNESS_AWAKE
+                    || mWakefulness == WAKEFULNESS_DREAMING
+                    || mWakefulness == WAKEFULNESS_DOZING) {
                 final int screenOffTimeout = getScreenOffTimeoutLocked();
                 final int screenDimDuration = getScreenDimDurationLocked(screenOffTimeout);
 
@@ -1380,8 +1266,7 @@
                         && mLastUserActivityTimeNoChangeLights >= mLastWakeTime) {
                     nextTimeout = mLastUserActivityTimeNoChangeLights + screenOffTimeout;
                     if (now < nextTimeout
-                            && mDisplayPowerRequest.screenState
-                                    != DisplayPowerRequest.SCREEN_STATE_OFF) {
+                            && mDisplayPowerRequest.wantScreenOnNormal()) {
                         mUserActivitySummary = mDisplayPowerRequest.screenState
                                 == DisplayPowerRequest.SCREEN_STATE_BRIGHT ?
                                 USER_ACTIVITY_SCREEN_BRIGHT : USER_ACTIVITY_SCREEN_DIM;
@@ -1443,7 +1328,7 @@
     /**
      * Updates the wakefulness of the device.
      *
-     * This is the function that decides whether the device should start napping
+     * This is the function that decides whether the device should start dreaming
      * based on the current wake locks and user activity state.  It may modify mDirty
      * if the wakefulness changes.
      *
@@ -1532,7 +1417,7 @@
     }
 
     /**
-     * Called when the device enters or exits a napping or dreaming state.
+     * Called when the device enters or exits a dreaming or dozing state.
      *
      * We do this asynchronously because we must call out of the power manager to start
      * the dream and we don't want to hold our lock while doing so.  There is a risk that
@@ -1540,46 +1425,60 @@
      */
     private void handleSandman() { // runs on handler thread
         // Handle preconditions.
-        boolean startDreaming = false;
+        final boolean startDreaming;
+        final int wakefulness;
         synchronized (mLock) {
             mSandmanScheduled = false;
-            boolean canDream = canDreamLocked();
-            if (DEBUG_SPEW) {
-                Slog.d(TAG, "handleSandman: canDream=" + canDream
-                        + ", mWakefulness=" + wakefulnessToString(mWakefulness));
-            }
-
-            if (canDream && mWakefulness == WAKEFULNESS_NAPPING) {
-                startDreaming = true;
+            wakefulness = mWakefulness;
+            if (mSandmanSummoned) {
+                startDreaming = ((wakefulness == WAKEFULNESS_DREAMING && canDreamLocked())
+                        || wakefulness == WAKEFULNESS_DOZING);
+                mSandmanSummoned = false;
+            } else {
+                startDreaming = false;
             }
         }
 
         // Start dreaming if needed.
         // We only control the dream on the handler thread, so we don't need to worry about
         // concurrent attempts to start or stop the dream.
-        boolean isDreaming = false;
+        final boolean isDreaming;
         if (mDreamManager != null) {
+            // Restart the dream whenever the sandman is summoned.
             if (startDreaming) {
-                mDreamManager.startDream();
+                mDreamManager.stopDream();
+                mDreamManager.startDream(wakefulness == WAKEFULNESS_DOZING);
             }
             isDreaming = mDreamManager.isDreaming();
+        } else {
+            isDreaming = false;
         }
 
         // Update dream state.
-        // We might need to stop the dream again if the preconditions changed.
-        boolean continueDreaming = false;
         synchronized (mLock) {
-            if (isDreaming && canDreamLocked()) {
-                if (mWakefulness == WAKEFULNESS_NAPPING) {
-                    mWakefulness = WAKEFULNESS_DREAMING;
-                    mDirty |= DIRTY_WAKEFULNESS;
-                    mBatteryLevelWhenDreamStarted = mBatteryLevel;
-                    updatePowerStateLocked();
-                    continueDreaming = true;
-                } else if (mWakefulness == WAKEFULNESS_DREAMING) {
-                    if (!isBeingKeptAwakeLocked()
+            // Remember the initial battery level when the dream started.
+            if (startDreaming && isDreaming) {
+                mBatteryLevelWhenDreamStarted = mBatteryLevel;
+                if (wakefulness == WAKEFULNESS_DOZING) {
+                    Slog.i(TAG, "Dozing...");
+                } else {
+                    Slog.i(TAG, "Dreaming...");
+                }
+            }
+
+            // If preconditions changed, wait for the next iteration to determine
+            // whether the dream should continue (or be restarted).
+            if (mSandmanSummoned || mWakefulness != wakefulness) {
+                return; // wait for next cycle
+            }
+
+            // Determine whether the dream should continue.
+            if (wakefulness == WAKEFULNESS_DREAMING) {
+                if (isDreaming && canDreamLocked()) {
+                    if (mDreamsBatteryLevelDrainCutoffConfig >= 0
                             && mBatteryLevel < mBatteryLevelWhenDreamStarted
-                                    - DREAM_BATTERY_LEVEL_DRAIN_CUTOFF) {
+                                    - mDreamsBatteryLevelDrainCutoffConfig
+                            && !isBeingKeptAwakeLocked()) {
                         // If the user activity timeout expired and the battery appears
                         // to be draining faster than it is charging then stop dreaming
                         // and go to sleep.
@@ -1589,53 +1488,64 @@
                                 + mBatteryLevelWhenDreamStarted + "%.  "
                                 + "Battery level now: " + mBatteryLevel + "%.");
                     } else {
-                        continueDreaming = true;
+                        return; // continue dreaming
                     }
                 }
-            }
-            if (!continueDreaming) {
-                handleDreamFinishedLocked();
+
+                // Dream has ended or will be stopped.  Update the power state.
+                if (isItBedTimeYetLocked()) {
+                    goToSleepNoUpdateLocked(SystemClock.uptimeMillis(),
+                            PowerManager.GO_TO_SLEEP_REASON_TIMEOUT);
+                    updatePowerStateLocked();
+                } else {
+                    wakeUpNoUpdateLocked(SystemClock.uptimeMillis());
+                    updatePowerStateLocked();
+                }
+            } else if (wakefulness == WAKEFULNESS_DOZING) {
+                if (isDreaming) {
+                    return; // continue dozing
+                }
+
+                // Doze has ended or will be stopped.  Update the power state.
+                reallyGoToSleepNoUpdateLocked(SystemClock.uptimeMillis());
+                updatePowerStateLocked();
             }
         }
 
-        // Stop dreaming if needed.
-        // It's possible that something else changed to make us need to start the dream again.
-        // If so, then the power manager will have posted another message to the handler
-        // to take care of it later.
-        if (mDreamManager != null) {
-            if (!continueDreaming) {
-                mDreamManager.stopDream();
-            }
+        // Stop dream.
+        if (isDreaming) {
+            mDreamManager.stopDream();
         }
     }
 
     /**
-     * Returns true if the device is allowed to dream in its current state
-     * assuming that it is currently napping or dreaming.
+     * Returns true if the device is allowed to dream in its current state.
+     * This function is not called when dozing.
      */
     private boolean canDreamLocked() {
-        return mDreamsSupportedConfig
-                && mDreamsEnabledSetting
-                && mDisplayPowerRequest.screenState != DisplayPowerRequest.SCREEN_STATE_OFF
-                && mBootCompleted
-                && (mIsPowered || isBeingKeptAwakeLocked());
-    }
-
-    /**
-     * Called when a dream is ending to figure out what to do next.
-     */
-    private void handleDreamFinishedLocked() {
-        if (mWakefulness == WAKEFULNESS_NAPPING
-                || mWakefulness == WAKEFULNESS_DREAMING) {
-            if (isItBedTimeYetLocked()) {
-                goToSleepNoUpdateLocked(SystemClock.uptimeMillis(),
-                        PowerManager.GO_TO_SLEEP_REASON_TIMEOUT);
-                updatePowerStateLocked();
-            } else {
-                wakeUpNoUpdateLocked(SystemClock.uptimeMillis());
-                updatePowerStateLocked();
+        if (mWakefulness != WAKEFULNESS_DREAMING
+                || !mDreamsSupportedConfig
+                || !mDreamsEnabledSetting
+                || !mDisplayPowerRequest.wantScreenOnNormal()
+                || !mBootCompleted) {
+            return false;
+        }
+        if (!isBeingKeptAwakeLocked()) {
+            if (!mIsPowered && !mDreamsEnabledOnBatteryConfig) {
+                return false;
+            }
+            if (!mIsPowered
+                    && mDreamsBatteryLevelMinimumWhenNotPoweredConfig >= 0
+                    && mBatteryLevel < mDreamsBatteryLevelMinimumWhenNotPoweredConfig) {
+                return false;
+            }
+            if (mIsPowered
+                    && mDreamsBatteryLevelMinimumWhenPoweredConfig >= 0
+                    && mBatteryLevel < mDreamsBatteryLevelMinimumWhenPoweredConfig) {
+                return false;
             }
         }
+        return true;
     }
 
     private void handleScreenOnBlockerReleased() {
@@ -1657,19 +1567,8 @@
         if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY | DIRTY_WAKEFULNESS
                 | DIRTY_ACTUAL_DISPLAY_POWER_STATE_UPDATED | DIRTY_BOOT_COMPLETED
                 | DIRTY_SETTINGS | DIRTY_SCREEN_ON_BLOCKER_RELEASED)) != 0) {
-            int newScreenState = getDesiredScreenPowerStateLocked();
-            if (newScreenState != mDisplayPowerRequest.screenState) {
-                if (newScreenState == DisplayPowerRequest.SCREEN_STATE_OFF
-                        && mDisplayPowerRequest.screenState
-                                != DisplayPowerRequest.SCREEN_STATE_OFF) {
-                    mLastScreenOffEventElapsedRealTime = SystemClock.elapsedRealtime();
-                }
-
-                mDisplayPowerRequest.screenState = newScreenState;
-                nativeSetPowerState(
-                        newScreenState != DisplayPowerRequest.SCREEN_STATE_OFF,
-                        newScreenState == DisplayPowerRequest.SCREEN_STATE_BRIGHT);
-            }
+            final int newScreenState = getDesiredScreenPowerStateLocked();
+            mDisplayPowerRequest.screenState = newScreenState;
 
             int screenBrightness = mScreenBrightnessSettingDefault;
             float screenAutoBrightnessAdjustment = 0.0f;
@@ -1707,7 +1606,7 @@
 
             mDisplayPowerRequest.blockScreenOn = mScreenOnBlocker.isHeld();
 
-            mDisplayReady = mDisplayPowerController.requestPowerState(mDisplayPowerRequest,
+            mDisplayReady = mDisplayManagerInternal.requestPowerState(mDisplayPowerRequest,
                     mRequestWaitForNegativeProximity);
             mRequestWaitForNegativeProximity = false;
 
@@ -1736,6 +1635,10 @@
             return DisplayPowerRequest.SCREEN_STATE_OFF;
         }
 
+        if ((mWakeLockSummary & WAKE_LOCK_DOZE) != 0) {
+            return DisplayPowerRequest.SCREEN_STATE_DOZE;
+        }
+
         if ((mWakeLockSummary & WAKE_LOCK_SCREEN_BRIGHT) != 0
                 || (mUserActivitySummary & USER_ACTIVITY_SCREEN_BRIGHT) != 0
                 || !mBootCompleted) {
@@ -1745,8 +1648,10 @@
         return DisplayPowerRequest.SCREEN_STATE_DIM;
     }
 
-    private final DisplayPowerController.Callbacks mDisplayPowerControllerCallbacks =
-            new DisplayPowerController.Callbacks() {
+    private final DisplayManagerInternal.DisplayPowerCallbacks mDisplayPowerCallbacks =
+            new DisplayManagerInternal.DisplayPowerCallbacks() {
+        private int mDisplayState = Display.STATE_UNKNOWN;
+
         @Override
         public void onStateChanged() {
             synchronized (mLock) {
@@ -1774,6 +1679,50 @@
                 updatePowerStateLocked();
             }
         }
+
+        @Override
+        public void onDisplayStateChange(int state) {
+            // This method is only needed to support legacy display blanking behavior
+            // where the display's power state is coupled to suspend or to the power HAL.
+            // The order of operations matters here.
+            synchronized (mLock) {
+                if (mDisplayState != state) {
+                    mDisplayState = state;
+                    if (state == Display.STATE_OFF) {
+                        if (!mDecoupleHalInteractiveModeFromDisplayConfig) {
+                            setHalInteractiveModeLocked(false);
+                        }
+                        if (!mDecoupleHalAutoSuspendModeFromDisplayConfig) {
+                            setHalAutoSuspendModeLocked(true);
+                        }
+                    } else {
+                        if (!mDecoupleHalAutoSuspendModeFromDisplayConfig) {
+                            setHalAutoSuspendModeLocked(false);
+                        }
+                        if (!mDecoupleHalInteractiveModeFromDisplayConfig) {
+                            setHalInteractiveModeLocked(true);
+                        }
+                    }
+                }
+            }
+        }
+
+        @Override
+        public void acquireSuspendBlocker() {
+            mDisplaySuspendBlocker.acquire();
+        }
+
+        @Override
+        public void releaseSuspendBlocker() {
+            mDisplaySuspendBlocker.release();
+        }
+
+        @Override
+        public String toString() {
+            synchronized (this) {
+                return "state=" + Display.stateToString(mDisplayState);
+            }
+        }
     };
 
     private boolean shouldUseProximitySensorLocked() {
@@ -1787,7 +1736,18 @@
      */
     private void updateSuspendBlockerLocked() {
         final boolean needWakeLockSuspendBlocker = ((mWakeLockSummary & WAKE_LOCK_CPU) != 0);
-        final boolean needDisplaySuspendBlocker = needDisplaySuspendBlocker();
+        final boolean needDisplaySuspendBlocker = needDisplaySuspendBlockerLocked();
+        final boolean autoSuspend = !needDisplaySuspendBlocker;
+
+        // Disable auto-suspend if needed.
+        if (!autoSuspend) {
+            if (mDecoupleHalAutoSuspendModeFromDisplayConfig) {
+                setHalAutoSuspendModeLocked(false);
+            }
+            if (mDecoupleHalInteractiveModeFromDisplayConfig) {
+                setHalInteractiveModeLocked(true);
+            }
+        }
 
         // First acquire suspend blockers if needed.
         if (needWakeLockSuspendBlocker && !mHoldingWakeLockSuspendBlocker) {
@@ -1808,17 +1768,27 @@
             mDisplaySuspendBlocker.release();
             mHoldingDisplaySuspendBlocker = false;
         }
+
+        // Enable auto-suspend if needed.
+        if (autoSuspend) {
+            if (mDecoupleHalInteractiveModeFromDisplayConfig) {
+                setHalInteractiveModeLocked(false);
+            }
+            if (mDecoupleHalAutoSuspendModeFromDisplayConfig) {
+                setHalAutoSuspendModeLocked(true);
+            }
+        }
     }
 
     /**
      * Return true if we must keep a suspend blocker active on behalf of the display.
      * We do so if the screen is on or is in transition between states.
      */
-    private boolean needDisplaySuspendBlocker() {
+    private boolean needDisplaySuspendBlockerLocked() {
         if (!mDisplayReady) {
             return true;
         }
-        if (mDisplayPowerRequest.screenState != DisplayPowerRequest.SCREEN_STATE_OFF) {
+        if (mDisplayPowerRequest.wantScreenOnNormal()) {
             // If we asked for the screen to be on but it is off due to the proximity
             // sensor then we may suspend but only if the configuration allows it.
             // On some hardware it may not be safe to suspend because the proximity
@@ -1828,23 +1798,33 @@
                 return true;
             }
         }
+        // Let the system suspend if the screen is off or dozing.
         return false;
     }
 
-    @Override // Binder call
-    public boolean isScreenOn() {
-        final long ident = Binder.clearCallingIdentity();
-        try {
-            return isScreenOnInternal();
-        } finally {
-            Binder.restoreCallingIdentity(ident);
+    private void setHalAutoSuspendModeLocked(boolean enable) {
+        if (enable != mHalAutoSuspendModeEnabled) {
+            if (DEBUG) {
+                Slog.d(TAG, "Setting HAL auto-suspend mode to " + enable);
+            }
+            mHalAutoSuspendModeEnabled = enable;
+            nativeSetAutoSuspend(enable);
         }
     }
 
-    private boolean isScreenOnInternal() {
+    private void setHalInteractiveModeLocked(boolean enable) {
+        if (enable != mHalInteractiveModeEnabled) {
+            if (DEBUG) {
+                Slog.d(TAG, "Setting HAL interactive mode to " + enable);
+            }
+            mHalInteractiveModeEnabled = enable;
+            nativeSetInteractive(enable);
+        }
+    }
+
+    private boolean isInteractiveInternal() {
         synchronized (mLock) {
-            return !mSystemReady
-                    || mDisplayPowerRequest.screenState != DisplayPowerRequest.SCREEN_STATE_OFF;
+            return mInteractive;
         }
     }
 
@@ -1885,43 +1865,6 @@
         updatePowerStateLocked();
     }
 
-    /**
-     * Reboots the device.
-     *
-     * @param confirm If true, shows a reboot confirmation dialog.
-     * @param reason The reason for the reboot, or null if none.
-     * @param wait If true, this call waits for the reboot to complete and does not return.
-     */
-    @Override // Binder call
-    public void reboot(boolean confirm, String reason, boolean wait) {
-        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.REBOOT, null);
-
-        final long ident = Binder.clearCallingIdentity();
-        try {
-            shutdownOrRebootInternal(false, confirm, reason, wait);
-        } finally {
-            Binder.restoreCallingIdentity(ident);
-        }
-    }
-
-    /**
-     * Shuts down the device.
-     *
-     * @param confirm If true, shows a shutdown confirmation dialog.
-     * @param wait If true, this call waits for the shutdown to complete and does not return.
-     */
-    @Override // Binder call
-    public void shutdown(boolean confirm, boolean wait) {
-        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.REBOOT, null);
-
-        final long ident = Binder.clearCallingIdentity();
-        try {
-            shutdownOrRebootInternal(true, confirm, null, wait);
-        } finally {
-            Binder.restoreCallingIdentity(ident);
-        }
-    }
-
     private void shutdownOrRebootInternal(final boolean shutdown, final boolean confirm,
             final String reason, boolean wait) {
         if (mHandler == null || !mSystemReady) {
@@ -1959,22 +1902,6 @@
         }
     }
 
-    /**
-     * Crash the runtime (causing a complete restart of the Android framework).
-     * Requires REBOOT permission.  Mostly for testing.  Should not return.
-     */
-    @Override // Binder call
-    public void crash(String message) {
-        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.REBOOT, null);
-
-        final long ident = Binder.clearCallingIdentity();
-        try {
-            crashInternal(message);
-        } finally {
-            Binder.restoreCallingIdentity(ident);
-        }
-    }
-
     private void crashInternal(final String message) {
         Thread t = new Thread("PowerManagerService.crash()") {
             @Override
@@ -1990,51 +1917,11 @@
         }
     }
 
-    /**
-     * Set the setting that determines whether the device stays on when plugged in.
-     * The argument is a bit string, with each bit specifying a power source that,
-     * when the device is connected to that source, causes the device to stay on.
-     * See {@link android.os.BatteryManager} for the list of power sources that
-     * can be specified. Current values include {@link android.os.BatteryManager#BATTERY_PLUGGED_AC}
-     * and {@link android.os.BatteryManager#BATTERY_PLUGGED_USB}
-     *
-     * Used by "adb shell svc power stayon ..."
-     *
-     * @param val an {@code int} containing the bits that specify which power sources
-     * should cause the device to stay on.
-     */
-    @Override // Binder call
-    public void setStayOnSetting(int val) {
-        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WRITE_SETTINGS, null);
-
-        final long ident = Binder.clearCallingIdentity();
-        try {
-            setStayOnSettingInternal(val);
-        } finally {
-            Binder.restoreCallingIdentity(ident);
-        }
-    }
-
     private void setStayOnSettingInternal(int val) {
         Settings.Global.putInt(mContext.getContentResolver(),
                 Settings.Global.STAY_ON_WHILE_PLUGGED_IN, val);
     }
 
-    /**
-     * Used by device administration to set the maximum screen off timeout.
-     *
-     * This method must only be called by the device administration policy manager.
-     */
-    @Override // Binder call
-    public void setMaximumScreenOffTimeoutFromDeviceAdmin(int timeMs) {
-        final long ident = Binder.clearCallingIdentity();
-        try {
-            setMaximumScreenOffTimeoutFromDeviceAdminInternal(timeMs);
-        } finally {
-            Binder.restoreCallingIdentity(ident);
-        }
-    }
-
     private void setMaximumScreenOffTimeoutFromDeviceAdminInternal(int timeMs) {
         synchronized (mLock) {
             mMaximumScreenOffTimeoutFromDeviceAdmin = timeMs;
@@ -2048,23 +1935,8 @@
                 && mMaximumScreenOffTimeoutFromDeviceAdmin < Integer.MAX_VALUE;
     }
 
-    /**
-     * Used by the phone application to make the attention LED flash when ringing.
-     */
-    @Override // Binder call
-    public void setAttentionLight(boolean on, int color) {
-        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
-
-        final long ident = Binder.clearCallingIdentity();
-        try {
-            setAttentionLightInternal(on, color);
-        } finally {
-            Binder.restoreCallingIdentity(ident);
-        }
-    }
-
     private void setAttentionLightInternal(boolean on, int color) {
-        LightsService.Light light;
+        Light light;
         synchronized (mLock) {
             if (!mSystemReady) {
                 return;
@@ -2073,38 +1945,7 @@
         }
 
         // Control light outside of lock.
-        light.setFlashing(color, LightsService.LIGHT_FLASH_HARDWARE, (on ? 3 : 0), 0);
-    }
-
-    /**
-     * Used by the Watchdog.
-     */
-    public long timeSinceScreenWasLastOn() {
-        synchronized (mLock) {
-            if (mDisplayPowerRequest.screenState != DisplayPowerRequest.SCREEN_STATE_OFF) {
-                return 0;
-            }
-            return SystemClock.elapsedRealtime() - mLastScreenOffEventElapsedRealTime;
-        }
-    }
-
-    /**
-     * Used by the window manager to override the screen brightness based on the
-     * current foreground activity.
-     *
-     * This method must only be called by the window manager.
-     *
-     * @param brightness The overridden brightness, or -1 to disable the override.
-     */
-    public void setScreenBrightnessOverrideFromWindowManager(int brightness) {
-        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
-
-        final long ident = Binder.clearCallingIdentity();
-        try {
-            setScreenBrightnessOverrideFromWindowManagerInternal(brightness);
-        } finally {
-            Binder.restoreCallingIdentity(ident);
-        }
+        light.setFlashing(color, Light.LIGHT_FLASH_HARDWARE, (on ? 3 : 0), 0);
     }
 
     private void setScreenBrightnessOverrideFromWindowManagerInternal(int brightness) {
@@ -2117,40 +1958,6 @@
         }
     }
 
-    /**
-     * Used by the window manager to override the button brightness based on the
-     * current foreground activity.
-     *
-     * This method must only be called by the window manager.
-     *
-     * @param brightness The overridden brightness, or -1 to disable the override.
-     */
-    public void setButtonBrightnessOverrideFromWindowManager(int brightness) {
-        // Do nothing.
-        // Button lights are not currently supported in the new implementation.
-        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
-    }
-
-    /**
-     * Used by the window manager to override the user activity timeout based on the
-     * current foreground activity.  It can only be used to make the timeout shorter
-     * than usual, not longer.
-     *
-     * This method must only be called by the window manager.
-     *
-     * @param timeoutMillis The overridden timeout, or -1 to disable the override.
-     */
-    public void setUserActivityTimeoutOverrideFromWindowManager(long timeoutMillis) {
-        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
-
-        final long ident = Binder.clearCallingIdentity();
-        try {
-            setUserActivityTimeoutOverrideFromWindowManagerInternal(timeoutMillis);
-        } finally {
-            Binder.restoreCallingIdentity(ident);
-        }
-    }
-
     private void setUserActivityTimeoutOverrideFromWindowManagerInternal(long timeoutMillis) {
         synchronized (mLock) {
             if (mUserActivityTimeoutOverrideFromWindowManager != timeoutMillis) {
@@ -2161,30 +1968,6 @@
         }
     }
 
-    /**
-     * Used by the settings application and brightness control widgets to
-     * temporarily override the current screen brightness setting so that the
-     * user can observe the effect of an intended settings change without applying
-     * it immediately.
-     *
-     * The override will be canceled when the setting value is next updated.
-     *
-     * @param brightness The overridden brightness.
-     *
-     * @see android.provider.Settings.System#SCREEN_BRIGHTNESS
-     */
-    @Override // Binder call
-    public void setTemporaryScreenBrightnessSettingOverride(int brightness) {
-        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
-
-        final long ident = Binder.clearCallingIdentity();
-        try {
-            setTemporaryScreenBrightnessSettingOverrideInternal(brightness);
-        } finally {
-            Binder.restoreCallingIdentity(ident);
-        }
-    }
-
     private void setTemporaryScreenBrightnessSettingOverrideInternal(int brightness) {
         synchronized (mLock) {
             if (mTemporaryScreenBrightnessSettingOverride != brightness) {
@@ -2195,30 +1978,6 @@
         }
     }
 
-    /**
-     * Used by the settings application and brightness control widgets to
-     * temporarily override the current screen auto-brightness adjustment setting so that the
-     * user can observe the effect of an intended settings change without applying
-     * it immediately.
-     *
-     * The override will be canceled when the setting value is next updated.
-     *
-     * @param adj The overridden brightness, or Float.NaN to disable the override.
-     *
-     * @see Settings.System#SCREEN_AUTO_BRIGHTNESS_ADJ
-     */
-    @Override // Binder call
-    public void setTemporaryScreenAutoBrightnessAdjustmentSettingOverride(float adj) {
-        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
-
-        final long ident = Binder.clearCallingIdentity();
-        try {
-            setTemporaryScreenAutoBrightnessAdjustmentSettingOverrideInternal(adj);
-        } finally {
-            Binder.restoreCallingIdentity(ident);
-        }
-    }
-
     private void setTemporaryScreenAutoBrightnessAdjustmentSettingOverrideInternal(float adj) {
         synchronized (mLock) {
             // Note: This condition handles NaN because NaN is not equal to any other
@@ -2265,24 +2024,15 @@
         }
     }
 
-    @Override // Binder call
-    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP)
-                != PackageManager.PERMISSION_GRANTED) {
-            pw.println("Permission Denial: can't dump PowerManager from from pid="
-                    + Binder.getCallingPid()
-                    + ", uid=" + Binder.getCallingUid());
-            return;
-        }
-
+    private void dumpInternal(PrintWriter pw) {
         pw.println("POWER MANAGER (dumpsys power)\n");
 
-        final DisplayPowerController dpc;
         final WirelessChargerDetector wcd;
         synchronized (mLock) {
             pw.println("Power Manager State:");
             pw.println("  mDirty=0x" + Integer.toHexString(mDirty));
             pw.println("  mWakefulness=" + wakefulnessToString(mWakefulness));
+            pw.println("  mInteractive=" + mInteractive);
             pw.println("  mIsPowered=" + mIsPowered);
             pw.println("  mPlugType=" + mPlugType);
             pw.println("  mBatteryLevel=" + mBatteryLevel);
@@ -2292,16 +2042,15 @@
             pw.println("  mProximityPositive=" + mProximityPositive);
             pw.println("  mBootCompleted=" + mBootCompleted);
             pw.println("  mSystemReady=" + mSystemReady);
+            pw.println("  mHalAutoSuspendModeEnabled=" + mHalAutoSuspendModeEnabled);
+            pw.println("  mHalInteractiveModeEnabled=" + mHalInteractiveModeEnabled);
             pw.println("  mWakeLockSummary=0x" + Integer.toHexString(mWakeLockSummary));
             pw.println("  mUserActivitySummary=0x" + Integer.toHexString(mUserActivitySummary));
             pw.println("  mRequestWaitForNegativeProximity=" + mRequestWaitForNegativeProximity);
             pw.println("  mSandmanScheduled=" + mSandmanScheduled);
+            pw.println("  mSandmanSummoned=" + mSandmanSummoned);
             pw.println("  mLastWakeTime=" + TimeUtils.formatUptime(mLastWakeTime));
             pw.println("  mLastSleepTime=" + TimeUtils.formatUptime(mLastSleepTime));
-            pw.println("  mSendWakeUpFinishedNotificationWhenReady="
-                    + mSendWakeUpFinishedNotificationWhenReady);
-            pw.println("  mSendGoToSleepFinishedNotificationWhenReady="
-                    + mSendGoToSleepFinishedNotificationWhenReady);
             pw.println("  mLastUserActivityTime=" + TimeUtils.formatUptime(mLastUserActivityTime));
             pw.println("  mLastUserActivityTimeNoChangeLights="
                     + TimeUtils.formatUptime(mLastUserActivityTimeNoChangeLights));
@@ -2311,6 +2060,10 @@
 
             pw.println();
             pw.println("Settings and Configuration:");
+            pw.println("  mDecoupleHalAutoSuspendModeFromDisplayConfig="
+                    + mDecoupleHalAutoSuspendModeFromDisplayConfig);
+            pw.println("  mDecoupleHalInteractiveModeFromDisplayConfig="
+                    + mDecoupleHalInteractiveModeFromDisplayConfig);
             pw.println("  mWakeUpWhenPluggedOrUnpluggedConfig="
                     + mWakeUpWhenPluggedOrUnpluggedConfig);
             pw.println("  mSuspendWhenScreenOffDueToProximityConfig="
@@ -2321,6 +2074,14 @@
                     + mDreamsActivatedOnSleepByDefaultConfig);
             pw.println("  mDreamsActivatedOnDockByDefaultConfig="
                     + mDreamsActivatedOnDockByDefaultConfig);
+            pw.println("  mDreamsEnabledOnBatteryConfig="
+                    + mDreamsEnabledOnBatteryConfig);
+            pw.println("  mDreamsBatteryLevelMinimumWhenPoweredConfig="
+                    + mDreamsBatteryLevelMinimumWhenPoweredConfig);
+            pw.println("  mDreamsBatteryLevelMinimumWhenNotPoweredConfig="
+                    + mDreamsBatteryLevelMinimumWhenNotPoweredConfig);
+            pw.println("  mDreamsBatteryLevelDrainCutoffConfig="
+                    + mDreamsBatteryLevelDrainCutoffConfig);
             pw.println("  mDreamsEnabledSetting=" + mDreamsEnabledSetting);
             pw.println("  mDreamsActivateOnSleepSetting=" + mDreamsActivateOnSleepSetting);
             pw.println("  mDreamsActivateOnDockSetting=" + mDreamsActivateOnDockSetting);
@@ -2367,16 +2128,11 @@
             pw.println("Screen On Blocker: " + mScreenOnBlocker);
 
             pw.println();
-            pw.println("Display Blanker: " + mDisplayBlanker);
+            pw.println("Display Power: " + mDisplayPowerCallbacks);
 
-            dpc = mDisplayPowerController;
             wcd = mWirelessChargerDetector;
         }
 
-        if (dpc != null) {
-            dpc.dump(pw);
-        }
-
         if (wcd != null) {
             wcd.dump(pw);
         }
@@ -2396,8 +2152,8 @@
                 return "Awake";
             case WAKEFULNESS_DREAMING:
                 return "Dreaming";
-            case WAKEFULNESS_NAPPING:
-                return "Napping";
+            case WAKEFULNESS_DOZING:
+                return "Dozing";
             default:
                 return Integer.toString(wakefulness);
         }
@@ -2574,6 +2330,7 @@
                     + " (uid=" + mOwnerUid + ", pid=" + mOwnerPid + ", ws=" + mWorkSource + ")";
         }
 
+        @SuppressWarnings("deprecation")
         private String getLockLevelString() {
             switch (mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK) {
                 case PowerManager.FULL_WAKE_LOCK:
@@ -2586,6 +2343,8 @@
                     return "PARTIAL_WAKE_LOCK             ";
                 case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK:
                     return "PROXIMITY_SCREEN_OFF_WAKE_LOCK";
+                case PowerManager.DOZE_WAKE_LOCK:
+                    return "DOZE_WAKE_LOCK                ";
                 default:
                     return "???                           ";
             }
@@ -2708,34 +2467,443 @@
         }
     }
 
-    private final class DisplayBlankerImpl implements DisplayBlanker {
-        private boolean mBlanked;
+    private final class BinderService extends IPowerManager.Stub {
+        @Override // Binder call
+        public void acquireWakeLockWithUid(IBinder lock, int flags, String tag,
+                String packageName, int uid) {
+            acquireWakeLock(lock, flags, tag, packageName, new WorkSource(uid));
+        }
 
+        @Override // Binder call
+        public void acquireWakeLock(IBinder lock, int flags, String tag, String packageName,
+                WorkSource ws) {
+            if (lock == null) {
+                throw new IllegalArgumentException("lock must not be null");
+            }
+            if (packageName == null) {
+                throw new IllegalArgumentException("packageName must not be null");
+            }
+            PowerManager.validateWakeLockParameters(flags, tag);
+
+            mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
+            if (ws != null && ws.size() != 0) {
+                mContext.enforceCallingOrSelfPermission(
+                        android.Manifest.permission.UPDATE_DEVICE_STATS, null);
+            } else {
+                ws = null;
+            }
+
+            final int uid = Binder.getCallingUid();
+            final int pid = Binder.getCallingPid();
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                acquireWakeLockInternal(lock, flags, tag, packageName, ws, uid, pid);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
+        @Override // Binder call
+        public void releaseWakeLock(IBinder lock, int flags) {
+            if (lock == null) {
+                throw new IllegalArgumentException("lock must not be null");
+            }
+
+            mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
+
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                releaseWakeLockInternal(lock, flags);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
+        @Override // Binder call
+        public void updateWakeLockUids(IBinder lock, int[] uids) {
+            WorkSource ws = null;
+
+            if (uids != null) {
+                ws = new WorkSource();
+                // XXX should WorkSource have a way to set uids as an int[] instead of adding them
+                // one at a time?
+                for (int i = 0; i < uids.length; i++) {
+                    ws.add(uids[i]);
+                }
+            }
+            updateWakeLockWorkSource(lock, ws);
+        }
+
+        @Override // Binder call
+        public void updateWakeLockWorkSource(IBinder lock, WorkSource ws) {
+            if (lock == null) {
+                throw new IllegalArgumentException("lock must not be null");
+            }
+
+            mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
+            if (ws != null && ws.size() != 0) {
+                mContext.enforceCallingOrSelfPermission(
+                        android.Manifest.permission.UPDATE_DEVICE_STATS, null);
+            } else {
+                ws = null;
+            }
+
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                updateWakeLockWorkSourceInternal(lock, ws);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
+        @Override // Binder call
+        public boolean isWakeLockLevelSupported(int level) {
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                return isWakeLockLevelSupportedInternal(level);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
+        @Override // Binder call
+        public void userActivity(long eventTime, int event, int flags) {
+            final long now = SystemClock.uptimeMillis();
+            if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER)
+                    != PackageManager.PERMISSION_GRANTED) {
+                // Once upon a time applications could call userActivity().
+                // Now we require the DEVICE_POWER permission.  Log a warning and ignore the
+                // request instead of throwing a SecurityException so we don't break old apps.
+                synchronized (mLock) {
+                    if (now >= mLastWarningAboutUserActivityPermission + (5 * 60 * 1000)) {
+                        mLastWarningAboutUserActivityPermission = now;
+                        Slog.w(TAG, "Ignoring call to PowerManager.userActivity() because the "
+                                + "caller does not have DEVICE_POWER permission.  "
+                                + "Please fix your app!  "
+                                + " pid=" + Binder.getCallingPid()
+                                + " uid=" + Binder.getCallingUid());
+                    }
+                }
+                return;
+            }
+
+            if (eventTime > SystemClock.uptimeMillis()) {
+                throw new IllegalArgumentException("event time must not be in the future");
+            }
+
+            final int uid = Binder.getCallingUid();
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                userActivityInternal(eventTime, event, flags, uid);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
+        @Override // Binder call
+        public void wakeUp(long eventTime) {
+            if (eventTime > SystemClock.uptimeMillis()) {
+                throw new IllegalArgumentException("event time must not be in the future");
+            }
+
+            mContext.enforceCallingOrSelfPermission(
+                    android.Manifest.permission.DEVICE_POWER, null);
+
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                wakeUpInternal(eventTime);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
+        @Override // Binder call
+        public void goToSleep(long eventTime, int reason) {
+            if (eventTime > SystemClock.uptimeMillis()) {
+                throw new IllegalArgumentException("event time must not be in the future");
+            }
+
+            mContext.enforceCallingOrSelfPermission(
+                    android.Manifest.permission.DEVICE_POWER, null);
+
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                goToSleepInternal(eventTime, reason);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
+        @Override // Binder call
+        public void nap(long eventTime) {
+            if (eventTime > SystemClock.uptimeMillis()) {
+                throw new IllegalArgumentException("event time must not be in the future");
+            }
+
+            mContext.enforceCallingOrSelfPermission(
+                    android.Manifest.permission.DEVICE_POWER, null);
+
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                napInternal(eventTime);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
+        @Override // Binder call
+        public boolean isInteractive() {
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                return isInteractiveInternal();
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
+        /**
+         * Reboots the device.
+         *
+         * @param confirm If true, shows a reboot confirmation dialog.
+         * @param reason The reason for the reboot, or null if none.
+         * @param wait If true, this call waits for the reboot to complete and does not return.
+         */
+        @Override // Binder call
+        public void reboot(boolean confirm, String reason, boolean wait) {
+            mContext.enforceCallingOrSelfPermission(android.Manifest.permission.REBOOT, null);
+
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                shutdownOrRebootInternal(false, confirm, reason, wait);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
+        /**
+         * Shuts down the device.
+         *
+         * @param confirm If true, shows a shutdown confirmation dialog.
+         * @param wait If true, this call waits for the shutdown to complete and does not return.
+         */
+        @Override // Binder call
+        public void shutdown(boolean confirm, boolean wait) {
+            mContext.enforceCallingOrSelfPermission(android.Manifest.permission.REBOOT, null);
+
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                shutdownOrRebootInternal(true, confirm, null, wait);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
+        /**
+         * Crash the runtime (causing a complete restart of the Android framework).
+         * Requires REBOOT permission.  Mostly for testing.  Should not return.
+         */
+        @Override // Binder call
+        public void crash(String message) {
+            mContext.enforceCallingOrSelfPermission(android.Manifest.permission.REBOOT, null);
+
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                crashInternal(message);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
+        /**
+         * Set the setting that determines whether the device stays on when plugged in.
+         * The argument is a bit string, with each bit specifying a power source that,
+         * when the device is connected to that source, causes the device to stay on.
+         * See {@link android.os.BatteryManager} for the list of power sources that
+         * can be specified. Current values include
+         * {@link android.os.BatteryManager#BATTERY_PLUGGED_AC}
+         * and {@link android.os.BatteryManager#BATTERY_PLUGGED_USB}
+         *
+         * Used by "adb shell svc power stayon ..."
+         *
+         * @param val an {@code int} containing the bits that specify which power sources
+         * should cause the device to stay on.
+         */
+        @Override // Binder call
+        public void setStayOnSetting(int val) {
+            mContext.enforceCallingOrSelfPermission(
+                    android.Manifest.permission.WRITE_SETTINGS, null);
+
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                setStayOnSettingInternal(val);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
+        /**
+         * Used by device administration to set the maximum screen off timeout.
+         *
+         * This method must only be called by the device administration policy manager.
+         */
+        @Override // Binder call
+        public void setMaximumScreenOffTimeoutFromDeviceAdmin(int timeMs) {
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                setMaximumScreenOffTimeoutFromDeviceAdminInternal(timeMs);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
+        /**
+         * Used by the settings application and brightness control widgets to
+         * temporarily override the current screen brightness setting so that the
+         * user can observe the effect of an intended settings change without applying
+         * it immediately.
+         *
+         * The override will be canceled when the setting value is next updated.
+         *
+         * @param brightness The overridden brightness.
+         *
+         * @see android.provider.Settings.System#SCREEN_BRIGHTNESS
+         */
+        @Override // Binder call
+        public void setTemporaryScreenBrightnessSettingOverride(int brightness) {
+            mContext.enforceCallingOrSelfPermission(
+                    android.Manifest.permission.DEVICE_POWER, null);
+
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                setTemporaryScreenBrightnessSettingOverrideInternal(brightness);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
+        /**
+         * Used by the settings application and brightness control widgets to
+         * temporarily override the current screen auto-brightness adjustment setting so that the
+         * user can observe the effect of an intended settings change without applying
+         * it immediately.
+         *
+         * The override will be canceled when the setting value is next updated.
+         *
+         * @param adj The overridden brightness, or Float.NaN to disable the override.
+         *
+         * @see android.provider.Settings.System#SCREEN_AUTO_BRIGHTNESS_ADJ
+         */
+        @Override // Binder call
+        public void setTemporaryScreenAutoBrightnessAdjustmentSettingOverride(float adj) {
+            mContext.enforceCallingOrSelfPermission(
+                    android.Manifest.permission.DEVICE_POWER, null);
+
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                setTemporaryScreenAutoBrightnessAdjustmentSettingOverrideInternal(adj);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
+        /**
+         * Used by the phone application to make the attention LED flash when ringing.
+         */
+        @Override // Binder call
+        public void setAttentionLight(boolean on, int color) {
+            mContext.enforceCallingOrSelfPermission(
+                    android.Manifest.permission.DEVICE_POWER, null);
+
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                setAttentionLightInternal(on, color);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
+        @Override // Binder call
+        protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+            if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP)
+                    != PackageManager.PERMISSION_GRANTED) {
+                pw.println("Permission Denial: can't dump PowerManager from from pid="
+                        + Binder.getCallingPid()
+                        + ", uid=" + Binder.getCallingUid());
+                return;
+            }
+
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                dumpInternal(pw);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+    }
+
+    private final class LocalService extends PowerManagerInternal {
+        /**
+         * Used by the window manager to override the screen brightness based on the
+         * current foreground activity.
+         *
+         * This method must only be called by the window manager.
+         *
+         * @param brightness The overridden brightness, or -1 to disable the override.
+         */
         @Override
-        public void blankAllDisplays() {
-            synchronized (this) {
-                mBlanked = true;
-                mDisplayManagerService.blankAllDisplaysFromPowerManager();
-                nativeSetInteractive(false);
-                nativeSetAutoSuspend(true);
+        public void setScreenBrightnessOverrideFromWindowManager(int brightness) {
+            mContext.enforceCallingOrSelfPermission(
+                    android.Manifest.permission.DEVICE_POWER, null);
+
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                setScreenBrightnessOverrideFromWindowManagerInternal(brightness);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
+        /**
+         * Used by the window manager to override the button brightness based on the
+         * current foreground activity.
+         *
+         * This method must only be called by the window manager.
+         *
+         * @param brightness The overridden brightness, or -1 to disable the override.
+         */
+        @Override
+        public void setButtonBrightnessOverrideFromWindowManager(int brightness) {
+            // Do nothing.
+            // Button lights are not currently supported in the new implementation.
+            mContext.enforceCallingOrSelfPermission(
+                    android.Manifest.permission.DEVICE_POWER, null);
+        }
+
+        /**
+         * Used by the window manager to override the user activity timeout based on the
+         * current foreground activity.  It can only be used to make the timeout shorter
+         * than usual, not longer.
+         *
+         * This method must only be called by the window manager.
+         *
+         * @param timeoutMillis The overridden timeout, or -1 to disable the override.
+         */
+        @Override
+        public void setUserActivityTimeoutOverrideFromWindowManager(long timeoutMillis) {
+            mContext.enforceCallingOrSelfPermission(
+                    android.Manifest.permission.DEVICE_POWER, null);
+
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                setUserActivityTimeoutOverrideFromWindowManagerInternal(timeoutMillis);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
             }
         }
 
         @Override
-        public void unblankAllDisplays() {
-            synchronized (this) {
-                nativeSetAutoSuspend(false);
-                nativeSetInteractive(true);
-                mDisplayManagerService.unblankAllDisplaysFromPowerManager();
-                mBlanked = false;
-            }
-        }
-
-        @Override
-        public String toString() {
-            synchronized (this) {
-                return "blanked=" + mBlanked;
-            }
+        public void setPolicy(WindowManagerPolicy policy) {
+            PowerManagerService.this.setPolicy(policy);
         }
     }
 }
diff --git a/services/java/com/android/server/power/ScreenOnBlocker.java b/services/core/java/com/android/server/power/ScreenOnBlocker.java
similarity index 100%
rename from services/java/com/android/server/power/ScreenOnBlocker.java
rename to services/core/java/com/android/server/power/ScreenOnBlocker.java
diff --git a/services/java/com/android/server/power/ShutdownThread.java b/services/core/java/com/android/server/power/ShutdownThread.java
similarity index 100%
rename from services/java/com/android/server/power/ShutdownThread.java
rename to services/core/java/com/android/server/power/ShutdownThread.java
diff --git a/services/java/com/android/server/power/SuspendBlocker.java b/services/core/java/com/android/server/power/SuspendBlocker.java
similarity index 100%
rename from services/java/com/android/server/power/SuspendBlocker.java
rename to services/core/java/com/android/server/power/SuspendBlocker.java
diff --git a/services/java/com/android/server/power/WirelessChargerDetector.java b/services/core/java/com/android/server/power/WirelessChargerDetector.java
similarity index 100%
rename from services/java/com/android/server/power/WirelessChargerDetector.java
rename to services/core/java/com/android/server/power/WirelessChargerDetector.java
diff --git a/services/java/com/android/server/search/SearchManagerService.java b/services/core/java/com/android/server/search/SearchManagerService.java
similarity index 100%
rename from services/java/com/android/server/search/SearchManagerService.java
rename to services/core/java/com/android/server/search/SearchManagerService.java
diff --git a/services/java/com/android/server/search/Searchables.java b/services/core/java/com/android/server/search/Searchables.java
similarity index 100%
rename from services/java/com/android/server/search/Searchables.java
rename to services/core/java/com/android/server/search/Searchables.java
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
new file mode 100644
index 0000000..4f75189
--- /dev/null
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
@@ -0,0 +1,29 @@
+/**
+ * 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.statusbar;
+
+import com.android.server.notification.NotificationDelegate;
+
+import android.os.IBinder;
+import android.service.notification.StatusBarNotification;
+
+public interface StatusBarManagerInternal {
+    void setNotificationDelegate(NotificationDelegate delegate);
+    IBinder addNotification(StatusBarNotification notification);
+    void updateNotification(IBinder key, StatusBarNotification notification);
+    void removeNotification(IBinder key);
+}
diff --git a/services/java/com/android/server/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
similarity index 80%
rename from services/java/com/android/server/StatusBarManagerService.java
rename to services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index f207c08..2ae467e 100644
--- a/services/java/com/android/server/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -14,26 +14,28 @@
  * limitations under the License.
  */
 
-package com.android.server;
+package com.android.server.statusbar;
 
 import android.app.StatusBarManager;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.UserHandle;
 import android.service.notification.StatusBarNotification;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
-import android.os.Binder;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.os.UserHandle;
 import android.util.Slog;
 
 import com.android.internal.statusbar.IStatusBar;
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.statusbar.StatusBarIcon;
 import com.android.internal.statusbar.StatusBarIconList;
+import com.android.server.LocalServices;
+import com.android.server.notification.NotificationDelegate;
 import com.android.server.wm.WindowManagerService;
 
 import java.io.FileDescriptor;
@@ -51,31 +53,31 @@
 public class StatusBarManagerService extends IStatusBarService.Stub
     implements WindowManagerService.OnHardKeyboardStatusChangeListener
 {
-    static final String TAG = "StatusBarManagerService";
-    static final boolean SPEW = false;
+    private static final String TAG = "StatusBarManagerService";
+    private static final boolean SPEW = false;
 
-    final Context mContext;
-    final WindowManagerService mWindowManager;
-    Handler mHandler = new Handler();
-    NotificationCallbacks mNotificationCallbacks;
-    volatile IStatusBar mBar;
-    StatusBarIconList mIcons = new StatusBarIconList();
-    HashMap<IBinder,StatusBarNotification> mNotifications
+    private final Context mContext;
+    private final WindowManagerService mWindowManager;
+    private Handler mHandler = new Handler();
+    private NotificationDelegate mNotificationDelegate;
+    private volatile IStatusBar mBar;
+    private StatusBarIconList mIcons = new StatusBarIconList();
+    private HashMap<IBinder,StatusBarNotification> mNotifications
             = new HashMap<IBinder,StatusBarNotification>();
 
     // for disabling the status bar
-    final ArrayList<DisableRecord> mDisableRecords = new ArrayList<DisableRecord>();
-    IBinder mSysUiVisToken = new Binder();
-    int mDisabled = 0;
+    private final ArrayList<DisableRecord> mDisableRecords = new ArrayList<DisableRecord>();
+    private IBinder mSysUiVisToken = new Binder();
+    private int mDisabled = 0;
 
-    Object mLock = new Object();
+    private Object mLock = new Object();
     // encompasses lights-out mode and other flags defined on View
-    int mSystemUiVisibility = 0;
-    boolean mMenuVisible = false;
-    int mImeWindowVis = 0;
-    int mImeBackDisposition;
-    IBinder mImeToken = null;
-    int mCurrentUserId;
+    private int mSystemUiVisibility = 0;
+    private boolean mMenuVisible = false;
+    private int mImeWindowVis = 0;
+    private int mImeBackDisposition;
+    private IBinder mImeToken = null;
+    private int mCurrentUserId;
 
     private class DisableRecord implements IBinder.DeathRecipient {
         int userId;
@@ -90,16 +92,6 @@
         }
     }
 
-    public interface NotificationCallbacks {
-        void onSetDisabled(int status);
-        void onClearAll();
-        void onNotificationClick(String pkg, String tag, int id);
-        void onNotificationClear(String pkg, String tag, int id);
-        void onPanelRevealed();
-        void onNotificationError(String pkg, String tag, int id,
-                int uid, int initialPid, String message);
-    }
-
     /**
      * Construct the service, add the status bar view to the window manager
      */
@@ -110,15 +102,74 @@
 
         final Resources res = context.getResources();
         mIcons.defineSlots(res.getStringArray(com.android.internal.R.array.config_statusBarIcons));
+
+        LocalServices.addService(StatusBarManagerInternal.class, mInternalService);
     }
 
-    public void setNotificationCallbacks(NotificationCallbacks listener) {
-        mNotificationCallbacks = listener;
-    }
+    /**
+     * Private API used by NotificationManagerService.
+     */
+    private final StatusBarManagerInternal mInternalService = new StatusBarManagerInternal() {
+        @Override
+        public void setNotificationDelegate(NotificationDelegate delegate) {
+            synchronized (mNotifications) {
+                mNotificationDelegate = delegate;
+            }
+        }
+
+        @Override
+        public IBinder addNotification(StatusBarNotification notification) {
+            synchronized (mNotifications) {
+                IBinder key = new Binder();
+                mNotifications.put(key, notification);
+                if (mBar != null) {
+                    try {
+                        mBar.addNotification(key, notification);
+                    } catch (RemoteException ex) {
+                    }
+                }
+                return key;
+            }
+        }
+
+        @Override
+        public void updateNotification(IBinder key, StatusBarNotification notification) {
+            synchronized (mNotifications) {
+                if (!mNotifications.containsKey(key)) {
+                    throw new IllegalArgumentException("updateNotification key not found: " + key);
+                }
+                mNotifications.put(key, notification);
+                if (mBar != null) {
+                    try {
+                        mBar.updateNotification(key, notification);
+                    } catch (RemoteException ex) {
+                    }
+                }
+            }
+        }
+
+        @Override
+        public void removeNotification(IBinder key) {
+            synchronized (mNotifications) {
+                final StatusBarNotification n = mNotifications.remove(key);
+                if (n == null) {
+                    Slog.e(TAG, "removeNotification key not found: " + key);
+                    return;
+                }
+                if (mBar != null) {
+                    try {
+                        mBar.removeNotification(key);
+                    } catch (RemoteException ex) {
+                    }
+                }
+            }
+        }
+    };
 
     // ================================================================================
     // From IStatusBarService
     // ================================================================================
+    @Override
     public void expandNotificationsPanel() {
         enforceExpandStatusBar();
 
@@ -130,6 +181,7 @@
         }
     }
 
+    @Override
     public void collapsePanels() {
         enforceExpandStatusBar();
 
@@ -141,6 +193,7 @@
         }
     }
 
+    @Override
     public void expandSettingsPanel() {
         enforceExpandStatusBar();
 
@@ -152,6 +205,7 @@
         }
     }
 
+    @Override
     public void disable(int what, IBinder token, String pkg) {
         disableInternal(mCurrentUserId, what, token, pkg);
     }
@@ -177,7 +231,7 @@
             mDisabled = net;
             mHandler.post(new Runnable() {
                     public void run() {
-                        mNotificationCallbacks.onSetDisabled(net);
+                        mNotificationDelegate.onSetDisabled(net);
                     }
                 });
             if (mBar != null) {
@@ -189,6 +243,7 @@
         }
     }
 
+    @Override
     public void setIcon(String slot, String iconPackage, int iconId, int iconLevel,
             String contentDescription) {
         enforceStatusBar();
@@ -214,6 +269,7 @@
         }
     }
 
+    @Override
     public void setIconVisibility(String slot, boolean visible) {
         enforceStatusBar();
 
@@ -241,6 +297,7 @@
         }
     }
 
+    @Override
     public void removeIcon(String slot) {
         enforceStatusBar();
 
@@ -265,6 +322,7 @@
      * Hide or show the on-screen Menu key. Only call this from the window manager, typically in
      * response to a window with FLAG_NEEDS_MENU_KEY set.
      */
+    @Override
     public void topAppWindowChanged(final boolean menuVisible) {
         enforceStatusBar();
 
@@ -285,6 +343,7 @@
         }
     }
 
+    @Override
     public void setImeWindowStatus(final IBinder token, final int vis, final int backDisposition) {
         enforceStatusBar();
 
@@ -312,6 +371,7 @@
         }
     }
 
+    @Override
     public void setSystemUiVisibility(int vis, int mask) {
         // also allows calls from window manager which is in this process.
         enforceStatusBarService();
@@ -344,6 +404,7 @@
         }
     }
 
+    @Override
     public void setHardKeyboardEnabled(final boolean enabled) {
         mHandler.post(new Runnable() {
             public void run() {
@@ -426,6 +487,7 @@
     // ================================================================================
     // Callbacks from the status bar service.
     // ================================================================================
+    @Override
     public void registerStatusBar(IStatusBar bar, StatusBarIconList iconList,
             List<IBinder> notificationKeys, List<StatusBarNotification> notifications,
             int switches[], List<IBinder> binders) {
@@ -458,86 +520,64 @@
      * The status bar service should call this each time the user brings the panel from
      * invisible to visible in order to clear the notification light.
      */
+    @Override
     public void onPanelRevealed() {
         enforceStatusBarService();
-
-        // tell the notification manager to turn off the lights.
-        mNotificationCallbacks.onPanelRevealed();
+        long identity = Binder.clearCallingIdentity();
+        try {
+            // tell the notification manager to turn off the lights.
+            mNotificationDelegate.onPanelRevealed();
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
     }
 
+    @Override
     public void onNotificationClick(String pkg, String tag, int id) {
         enforceStatusBarService();
-
-        mNotificationCallbacks.onNotificationClick(pkg, tag, id);
+        long identity = Binder.clearCallingIdentity();
+        try {
+            mNotificationDelegate.onNotificationClick(pkg, tag, id);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
     }
 
+    @Override
     public void onNotificationError(String pkg, String tag, int id,
             int uid, int initialPid, String message) {
         enforceStatusBarService();
-
-        // WARNING: this will call back into us to do the remove.  Don't hold any locks.
-        mNotificationCallbacks.onNotificationError(pkg, tag, id, uid, initialPid, message);
+        long identity = Binder.clearCallingIdentity();
+        try {
+            // WARNING: this will call back into us to do the remove.  Don't hold any locks.
+            mNotificationDelegate.onNotificationError(pkg, tag, id, uid, initialPid, message);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
     }
 
+    @Override
     public void onNotificationClear(String pkg, String tag, int id) {
         enforceStatusBarService();
-
-        mNotificationCallbacks.onNotificationClear(pkg, tag, id);
+        long identity = Binder.clearCallingIdentity();
+        try {
+            mNotificationDelegate.onNotificationClear(pkg, tag, id);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
     }
 
+    @Override
     public void onClearAllNotifications() {
         enforceStatusBarService();
-
-        mNotificationCallbacks.onClearAll();
-    }
-
-    // ================================================================================
-    // Callbacks for NotificationManagerService.
-    // ================================================================================
-    public IBinder addNotification(StatusBarNotification notification) {
-        synchronized (mNotifications) {
-            IBinder key = new Binder();
-            mNotifications.put(key, notification);
-            if (mBar != null) {
-                try {
-                    mBar.addNotification(key, notification);
-                } catch (RemoteException ex) {
-                }
-            }
-            return key;
+        long identity = Binder.clearCallingIdentity();
+        try {
+            mNotificationDelegate.onClearAll();
+        } finally {
+            Binder.restoreCallingIdentity(identity);
         }
     }
 
-    public void updateNotification(IBinder key, StatusBarNotification notification) {
-        synchronized (mNotifications) {
-            if (!mNotifications.containsKey(key)) {
-                throw new IllegalArgumentException("updateNotification key not found: " + key);
-            }
-            mNotifications.put(key, notification);
-            if (mBar != null) {
-                try {
-                    mBar.updateNotification(key, notification);
-                } catch (RemoteException ex) {
-                }
-            }
-        }
-    }
-
-    public void removeNotification(IBinder key) {
-        synchronized (mNotifications) {
-            final StatusBarNotification n = mNotifications.remove(key);
-            if (n == null) {
-                Slog.e(TAG, "removeNotification key not found: " + key);
-                return;
-            }
-            if (mBar != null) {
-                try {
-                    mBar.removeNotification(key);
-                } catch (RemoteException ex) {
-                }
-            }
-        }
-    }
 
     // ================================================================================
     // Can be called from any thread
diff --git a/services/java/com/android/server/power/DisplayBlanker.java b/services/core/java/com/android/server/storage/DeviceStorageMonitorInternal.java
similarity index 64%
copy from services/java/com/android/server/power/DisplayBlanker.java
copy to services/core/java/com/android/server/storage/DeviceStorageMonitorInternal.java
index 6072053..a91a81b 100644
--- a/services/java/com/android/server/power/DisplayBlanker.java
+++ b/services/core/java/com/android/server/storage/DeviceStorageMonitorInternal.java
@@ -1,11 +1,11 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
+/**
+ * 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
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,12 +14,11 @@
  * limitations under the License.
  */
 
-package com.android.server.power;
+package com.android.server.storage;
 
-/**
- * Blanks or unblanks all displays.
- */
-interface DisplayBlanker {
-    public void blankAllDisplays();
-    public void unblankAllDisplays();
+public interface DeviceStorageMonitorInternal {
+    boolean isMemoryLow();
+    long getMemoryLowThreshold();
+    void checkMemory();
 }
+
diff --git a/services/java/com/android/server/DeviceStorageMonitorService.java b/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
similarity index 77%
rename from services/java/com/android/server/DeviceStorageMonitorService.java
rename to services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
index 016c561..43a99e0 100644
--- a/services/java/com/android/server/DeviceStorageMonitorService.java
+++ b/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
@@ -14,7 +14,10 @@
  * limitations under the License.
  */
 
-package com.android.server;
+package com.android.server.storage;
+
+import com.android.server.EventLogTags;
+import com.android.server.SystemService;
 
 import android.app.Notification;
 import android.app.NotificationManager;
@@ -29,8 +32,8 @@
 import android.os.Environment;
 import android.os.FileObserver;
 import android.os.Handler;
+import android.os.IBinder;
 import android.os.Message;
-import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.StatFs;
@@ -66,13 +69,13 @@
  * settings parameter with a default value of 2MB), the free memory is
  * logged to the event log.
  */
-public class DeviceStorageMonitorService extends Binder {
-    private static final String TAG = "DeviceStorageMonitorService";
+public class DeviceStorageMonitorService extends SystemService {
+    static final String TAG = "DeviceStorageMonitorService";
 
-    private static final boolean DEBUG = false;
-    private static final boolean localLOGV = false;
+    static final boolean DEBUG = false;
+    static final boolean localLOGV = false;
 
-    private static final int DEVICE_MEMORY_WHAT = 1;
+    static final int DEVICE_MEMORY_WHAT = 1;
     private static final int MONITOR_INTERVAL = 1; //in minutes
     private static final int LOW_MEMORY_NOTIFICATION_ID = 1;
 
@@ -84,33 +87,32 @@
     private long mFreeMemAfterLastCacheClear;  // on /data
     private long mLastReportedFreeMem;
     private long mLastReportedFreeMemTime;
-    private boolean mLowMemFlag=false;
+    boolean mLowMemFlag=false;
     private boolean mMemFullFlag=false;
-    private Context mContext;
-    private ContentResolver mResolver;
-    private long mTotalMemory;  // on /data
-    private StatFs mDataFileStats;
-    private StatFs mSystemFileStats;
-    private StatFs mCacheFileStats;
+    private final ContentResolver mResolver;
+    private final long mTotalMemory;  // on /data
+    private final StatFs mDataFileStats;
+    private final StatFs mSystemFileStats;
+    private final StatFs mCacheFileStats;
 
     private static final File DATA_PATH = Environment.getDataDirectory();
     private static final File SYSTEM_PATH = Environment.getRootDirectory();
     private static final File CACHE_PATH = Environment.getDownloadCacheDirectory();
 
     private long mThreadStartTime = -1;
-    private boolean mClearSucceeded = false;
-    private boolean mClearingCache;
-    private Intent mStorageLowIntent;
-    private Intent mStorageOkIntent;
-    private Intent mStorageFullIntent;
-    private Intent mStorageNotFullIntent;
+    boolean mClearSucceeded = false;
+    boolean mClearingCache;
+    private final Intent mStorageLowIntent;
+    private final Intent mStorageOkIntent;
+    private final Intent mStorageFullIntent;
+    private final Intent mStorageNotFullIntent;
     private CachePackageDataObserver mClearCacheObserver;
-    private final CacheFileDeletedObserver mCacheFileDeletedObserver;
+    private CacheFileDeletedObserver mCacheFileDeletedObserver;
     private static final int _TRUE = 1;
     private static final int _FALSE = 0;
     // This is the raw threshold that has been set at which we consider
     // storage to be low.
-    private long mMemLowThreshold;
+    long mMemLowThreshold;
     // This is the threshold at which we start trying to flush caches
     // to get below the low threshold limit.  It is less than the low
     // threshold; we will allow storage to get a bit beyond the limit
@@ -126,13 +128,13 @@
     /**
      * This string is used for ServiceManager access to this class.
      */
-    public static final String SERVICE = "devicestoragemonitor";
+    static final String SERVICE = "devicestoragemonitor";
 
     /**
     * Handler that checks the amount of disk space on the device and sends a
     * notification if the device runs low on disk space
     */
-    Handler mHandler = new Handler() {
+    private final Handler mHandler = new Handler() {
         @Override
         public void handleMessage(Message msg) {
             //don't handle an invalid message
@@ -144,7 +146,7 @@
         }
     };
 
-    class CachePackageDataObserver extends IPackageDataObserver.Stub {
+    private class CachePackageDataObserver extends IPackageDataObserver.Stub {
         public void onRemoveCompleted(String packageName, boolean succeeded) {
             mClearSucceeded = succeeded;
             mClearingCache = false;
@@ -154,7 +156,7 @@
         }
     }
 
-    private final void restatDataDir() {
+    private void restatDataDir() {
         try {
             mDataFileStats.restat(DATA_PATH.getAbsolutePath());
             mFreeMem = (long) mDataFileStats.getAvailableBlocks() *
@@ -206,7 +208,7 @@
         }
     }
 
-    private final void clearCache() {
+    private void clearCache() {
         if (mClearCacheObserver == null) {
             // Lazy instantiation
             mClearCacheObserver = new CachePackageDataObserver();
@@ -223,7 +225,7 @@
         }
     }
 
-    private final void checkMemory(boolean checkCache) {
+    void checkMemory(boolean checkCache) {
         //if the thread that was started to clear cache is still running do nothing till its
         //finished clearing cache. Ideally this flag could be modified by clearCache
         // and should be accessed via a lock but even if it does this test will fail now and
@@ -300,7 +302,7 @@
         postCheckMemoryMsg(true, DEFAULT_CHECK_INTERVAL);
     }
 
-    private void postCheckMemoryMsg(boolean clearCache, long delay) {
+    void postCheckMemoryMsg(boolean clearCache, long delay) {
         // Remove queued messages
         mHandler.removeMessages(DEVICE_MEMORY_WHAT);
         mHandler.sendMessageDelayed(mHandler.obtainMessage(DEVICE_MEMORY_WHAT,
@@ -308,14 +310,10 @@
                 delay);
     }
 
-    /**
-    * Constructor to run service. initializes the disk space threshold value
-    * and posts an empty message to kickstart the process.
-    */
     public DeviceStorageMonitorService(Context context) {
+        super(context);
         mLastReportedFreeMemTime = 0;
-        mContext = context;
-        mResolver = mContext.getContentResolver();
+        mResolver = context.getContentResolver();
         //create StatFs object
         mDataFileStats = new StatFs(DATA_PATH.getAbsolutePath());
         mSystemFileStats = new StatFs(SYSTEM_PATH.getAbsolutePath());
@@ -331,9 +329,16 @@
         mStorageFullIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
         mStorageNotFullIntent = new Intent(Intent.ACTION_DEVICE_STORAGE_NOT_FULL);
         mStorageNotFullIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+    }
 
+    /**
+    * Initializes the disk space threshold value and posts an empty message to
+    * kickstart the process.
+    */
+    @Override
+    public void onStart() {
         // cache storage thresholds
-        final StorageManager sm = StorageManager.from(context);
+        final StorageManager sm = StorageManager.from(getContext());
         mMemLowThreshold = sm.getStorageLowBytes(DATA_PATH);
         mMemFullThreshold = sm.getStorageFullBytes(DATA_PATH);
 
@@ -345,6 +350,78 @@
 
         mCacheFileDeletedObserver = new CacheFileDeletedObserver();
         mCacheFileDeletedObserver.startWatching();
+
+        publishBinderService(SERVICE, mRemoteService);
+        publishLocalService(DeviceStorageMonitorInternal.class, mLocalService);
+    }
+
+    private final DeviceStorageMonitorInternal mLocalService = new DeviceStorageMonitorInternal() {
+        @Override
+        public void checkMemory() {
+            // force an early check
+            postCheckMemoryMsg(true, 0);
+        }
+
+        @Override
+        public boolean isMemoryLow() {
+            return mLowMemFlag;
+        }
+
+        @Override
+        public long getMemoryLowThreshold() {
+            return mMemLowThreshold;
+        }
+    };
+
+    private final IBinder mRemoteService = new Binder() {
+        @Override
+        protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+            if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+                    != PackageManager.PERMISSION_GRANTED) {
+
+                pw.println("Permission Denial: can't dump " + SERVICE + " from from pid="
+                        + Binder.getCallingPid()
+                        + ", uid=" + Binder.getCallingUid());
+                return;
+            }
+
+            dumpImpl(pw);
+        }
+    };
+
+    void dumpImpl(PrintWriter pw) {
+        final Context context = getContext();
+
+        pw.println("Current DeviceStorageMonitor state:");
+
+        pw.print("  mFreeMem="); pw.print(Formatter.formatFileSize(context, mFreeMem));
+        pw.print(" mTotalMemory=");
+        pw.println(Formatter.formatFileSize(context, mTotalMemory));
+
+        pw.print("  mFreeMemAfterLastCacheClear=");
+        pw.println(Formatter.formatFileSize(context, mFreeMemAfterLastCacheClear));
+
+        pw.print("  mLastReportedFreeMem=");
+        pw.print(Formatter.formatFileSize(context, mLastReportedFreeMem));
+        pw.print(" mLastReportedFreeMemTime=");
+        TimeUtils.formatDuration(mLastReportedFreeMemTime, SystemClock.elapsedRealtime(), pw);
+        pw.println();
+
+        pw.print("  mLowMemFlag="); pw.print(mLowMemFlag);
+        pw.print(" mMemFullFlag="); pw.println(mMemFullFlag);
+
+        pw.print("  mClearSucceeded="); pw.print(mClearSucceeded);
+        pw.print(" mClearingCache="); pw.println(mClearingCache);
+
+        pw.print("  mMemLowThreshold=");
+        pw.print(Formatter.formatFileSize(context, mMemLowThreshold));
+        pw.print(" mMemFullThreshold=");
+        pw.println(Formatter.formatFileSize(context, mMemFullThreshold));
+
+        pw.print("  mMemCacheStartTrimThreshold=");
+        pw.print(Formatter.formatFileSize(context, mMemCacheStartTrimThreshold));
+        pw.print(" mMemCacheTrimToThreshold=");
+        pw.println(Formatter.formatFileSize(context, mMemCacheTrimToThreshold));
     }
 
     /**
@@ -352,7 +429,8 @@
     * an error dialog indicating low disk space and launch the Installer
     * application
     */
-    private final void sendNotification() {
+    private void sendNotification() {
+        final Context context = getContext();
         if(localLOGV) Slog.i(TAG, "Sending low memory notification");
         //log the event to event log with the amount of free storage(in bytes) left on the device
         EventLog.writeEvent(EventLogTags.LOW_STORAGE, mFreeMem);
@@ -363,86 +441,58 @@
         lowMemIntent.putExtra("memory", mFreeMem);
         lowMemIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         NotificationManager mNotificationMgr =
-                (NotificationManager)mContext.getSystemService(
+                (NotificationManager)context.getSystemService(
                         Context.NOTIFICATION_SERVICE);
-        CharSequence title = mContext.getText(
+        CharSequence title = context.getText(
                 com.android.internal.R.string.low_internal_storage_view_title);
-        CharSequence details = mContext.getText(
+        CharSequence details = context.getText(
                 com.android.internal.R.string.low_internal_storage_view_text);
-        PendingIntent intent = PendingIntent.getActivityAsUser(mContext, 0,  lowMemIntent, 0,
+        PendingIntent intent = PendingIntent.getActivityAsUser(context, 0,  lowMemIntent, 0,
                 null, UserHandle.CURRENT);
         Notification notification = new Notification();
         notification.icon = com.android.internal.R.drawable.stat_notify_disk_full;
         notification.tickerText = title;
         notification.flags |= Notification.FLAG_NO_CLEAR;
-        notification.setLatestEventInfo(mContext, title, details, intent);
+        notification.setLatestEventInfo(context, title, details, intent);
         mNotificationMgr.notifyAsUser(null, LOW_MEMORY_NOTIFICATION_ID, notification,
                 UserHandle.ALL);
-        mContext.sendStickyBroadcastAsUser(mStorageLowIntent, UserHandle.ALL);
+        context.sendStickyBroadcastAsUser(mStorageLowIntent, UserHandle.ALL);
     }
 
     /**
      * Cancels low storage notification and sends OK intent.
      */
-    private final void cancelNotification() {
+    private void cancelNotification() {
+        final Context context = getContext();
         if(localLOGV) Slog.i(TAG, "Canceling low memory notification");
         NotificationManager mNotificationMgr =
-                (NotificationManager)mContext.getSystemService(
+                (NotificationManager)context.getSystemService(
                         Context.NOTIFICATION_SERVICE);
         //cancel notification since memory has been freed
         mNotificationMgr.cancelAsUser(null, LOW_MEMORY_NOTIFICATION_ID, UserHandle.ALL);
 
-        mContext.removeStickyBroadcastAsUser(mStorageLowIntent, UserHandle.ALL);
-        mContext.sendBroadcastAsUser(mStorageOkIntent, UserHandle.ALL);
+        context.removeStickyBroadcastAsUser(mStorageLowIntent, UserHandle.ALL);
+        context.sendBroadcastAsUser(mStorageOkIntent, UserHandle.ALL);
     }
 
     /**
      * Send a notification when storage is full.
      */
-    private final void sendFullNotification() {
+    private void sendFullNotification() {
         if(localLOGV) Slog.i(TAG, "Sending memory full notification");
-        mContext.sendStickyBroadcastAsUser(mStorageFullIntent, UserHandle.ALL);
+        getContext().sendStickyBroadcastAsUser(mStorageFullIntent, UserHandle.ALL);
     }
 
     /**
      * Cancels memory full notification and sends "not full" intent.
      */
-    private final void cancelFullNotification() {
+    private void cancelFullNotification() {
         if(localLOGV) Slog.i(TAG, "Canceling memory full notification");
-        mContext.removeStickyBroadcastAsUser(mStorageFullIntent, UserHandle.ALL);
-        mContext.sendBroadcastAsUser(mStorageNotFullIntent, UserHandle.ALL);
+        getContext().removeStickyBroadcastAsUser(mStorageFullIntent, UserHandle.ALL);
+        getContext().sendBroadcastAsUser(mStorageNotFullIntent, UserHandle.ALL);
     }
 
-    public void updateMemory() {
-        int callingUid = getCallingUid();
-        if(callingUid != Process.SYSTEM_UID) {
-            return;
-        }
-        // force an early check
-        postCheckMemoryMsg(true, 0);
-    }
-
-    /**
-     * Callable from other things in the system service to obtain the low memory
-     * threshold.
-     * 
-     * @return low memory threshold in bytes
-     */
-    public long getMemoryLowThreshold() {
-        return mMemLowThreshold;
-    }
-
-    /**
-     * Callable from other things in the system process to check whether memory
-     * is low.
-     * 
-     * @return true is memory is low
-     */
-    public boolean isMemoryLow() {
-        return mLowMemFlag;
-    }
-
-    public static class CacheFileDeletedObserver extends FileObserver {
+    private static class CacheFileDeletedObserver extends FileObserver {
         public CacheFileDeletedObserver() {
             super(Environment.getDownloadCacheDirectory().getAbsolutePath(), FileObserver.DELETE);
         }
@@ -452,40 +502,4 @@
             EventLogTags.writeCacheFileDeleted(path);
         }
     }
-
-    @Override
-    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
-                != PackageManager.PERMISSION_GRANTED) {
-
-            pw.println("Permission Denial: can't dump " + SERVICE + " from from pid="
-                    + Binder.getCallingPid()
-                    + ", uid=" + Binder.getCallingUid());
-            return;
-        }
-
-        pw.println("Current DeviceStorageMonitor state:");
-        pw.print("  mFreeMem="); pw.print(Formatter.formatFileSize(mContext, mFreeMem));
-                pw.print(" mTotalMemory=");
-                pw.println(Formatter.formatFileSize(mContext, mTotalMemory));
-        pw.print("  mFreeMemAfterLastCacheClear=");
-                pw.println(Formatter.formatFileSize(mContext, mFreeMemAfterLastCacheClear));
-        pw.print("  mLastReportedFreeMem=");
-                pw.print(Formatter.formatFileSize(mContext, mLastReportedFreeMem));
-                pw.print(" mLastReportedFreeMemTime=");
-                TimeUtils.formatDuration(mLastReportedFreeMemTime, SystemClock.elapsedRealtime(), pw);
-                pw.println();
-        pw.print("  mLowMemFlag="); pw.print(mLowMemFlag);
-                pw.print(" mMemFullFlag="); pw.println(mMemFullFlag);
-        pw.print("  mClearSucceeded="); pw.print(mClearSucceeded);
-                pw.print(" mClearingCache="); pw.println(mClearingCache);
-        pw.print("  mMemLowThreshold=");
-                pw.print(Formatter.formatFileSize(mContext, mMemLowThreshold));
-                pw.print(" mMemFullThreshold=");
-                pw.println(Formatter.formatFileSize(mContext, mMemFullThreshold));
-        pw.print("  mMemCacheStartTrimThreshold=");
-                pw.print(Formatter.formatFileSize(mContext, mMemCacheStartTrimThreshold));
-                pw.print(" mMemCacheTrimToThreshold=");
-                pw.println(Formatter.formatFileSize(mContext, mMemCacheTrimToThreshold));
-    }
 }
diff --git a/services/java/com/android/server/power/DisplayBlanker.java b/services/core/java/com/android/server/twilight/TwilightListener.java
similarity index 70%
copy from services/java/com/android/server/power/DisplayBlanker.java
copy to services/core/java/com/android/server/twilight/TwilightListener.java
index 6072053..29ead44 100644
--- a/services/java/com/android/server/power/DisplayBlanker.java
+++ b/services/core/java/com/android/server/twilight/TwilightListener.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 The Android Open Source Project
+ * 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.
@@ -14,12 +14,8 @@
  * limitations under the License.
  */
 
-package com.android.server.power;
+package com.android.server.twilight;
 
-/**
- * Blanks or unblanks all displays.
- */
-interface DisplayBlanker {
-    public void blankAllDisplays();
-    public void unblankAllDisplays();
-}
+public interface TwilightListener {
+    void onTwilightStateChanged();
+}
\ No newline at end of file
diff --git a/services/java/com/android/server/power/DisplayBlanker.java b/services/core/java/com/android/server/twilight/TwilightManager.java
similarity index 68%
copy from services/java/com/android/server/power/DisplayBlanker.java
copy to services/core/java/com/android/server/twilight/TwilightManager.java
index 6072053..b3de58b 100644
--- a/services/java/com/android/server/power/DisplayBlanker.java
+++ b/services/core/java/com/android/server/twilight/TwilightManager.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 The Android Open Source Project
+ * 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.
@@ -14,12 +14,11 @@
  * limitations under the License.
  */
 
-package com.android.server.power;
+package com.android.server.twilight;
 
-/**
- * Blanks or unblanks all displays.
- */
-interface DisplayBlanker {
-    public void blankAllDisplays();
-    public void unblankAllDisplays();
+import android.os.Handler;
+
+public interface TwilightManager {
+    void registerListener(TwilightListener listener, Handler handler);
+    TwilightState getCurrentState();
 }
diff --git a/services/java/com/android/server/TwilightService.java b/services/core/java/com/android/server/twilight/TwilightService.java
similarity index 74%
rename from services/java/com/android/server/TwilightService.java
rename to services/core/java/com/android/server/twilight/TwilightService.java
index 0356faa..a71961c 100644
--- a/services/java/com/android/server/TwilightService.java
+++ b/services/core/java/com/android/server/twilight/TwilightService.java
@@ -14,7 +14,10 @@
  * limitations under the License.
  */
 
-package com.android.server;
+package com.android.server.twilight;
+
+import com.android.server.SystemService;
+import com.android.server.TwilightCalculator;
 
 import android.app.AlarmManager;
 import android.app.PendingIntent;
@@ -34,9 +37,7 @@
 import android.text.format.Time;
 import android.util.Slog;
 
-import java.text.DateFormat;
 import java.util.ArrayList;
-import java.util.Date;
 import java.util.Iterator;
 
 import libcore.util.Objects;
@@ -47,78 +48,92 @@
  * Used by the UI mode manager and other components to adjust night mode
  * effects based on sunrise and sunset.
  */
-public final class TwilightService {
-    private static final String TAG = "TwilightService";
-
-    private static final boolean DEBUG = false;
-
-    private static final String ACTION_UPDATE_TWILIGHT_STATE =
+public final class TwilightService extends SystemService {
+    static final String TAG = "TwilightService";
+    static final boolean DEBUG = false;
+    static final String ACTION_UPDATE_TWILIGHT_STATE =
             "com.android.server.action.UPDATE_TWILIGHT_STATE";
 
-    private final Context mContext;
-    private final AlarmManager mAlarmManager;
-    private final LocationManager mLocationManager;
-    private final LocationHandler mLocationHandler;
+    final Object mLock = new Object();
 
-    private final Object mLock = new Object();
+    AlarmManager mAlarmManager;
+    LocationManager mLocationManager;
+    LocationHandler mLocationHandler;
 
-    private final ArrayList<TwilightListenerRecord> mListeners =
+    final ArrayList<TwilightListenerRecord> mListeners =
             new ArrayList<TwilightListenerRecord>();
 
-    private boolean mSystemReady;
-
-    private TwilightState mTwilightState;
+    TwilightState mTwilightState;
 
     public TwilightService(Context context) {
-        mContext = context;
+        super(context);
+    }
 
-        mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
-        mLocationManager = (LocationManager)mContext.getSystemService(Context.LOCATION_SERVICE);
+    @Override
+    public void onStart() {
+        mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
+        mLocationManager = (LocationManager) getContext().getSystemService(
+                Context.LOCATION_SERVICE);
         mLocationHandler = new LocationHandler();
+
+        IntentFilter filter = new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED);
+        filter.addAction(Intent.ACTION_TIME_CHANGED);
+        filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
+        filter.addAction(ACTION_UPDATE_TWILIGHT_STATE);
+        getContext().registerReceiver(mUpdateLocationReceiver, filter);
+
+        publishLocalService(TwilightManager.class, mService);
     }
 
-    void systemReady() {
-        synchronized (mLock) {
-            mSystemReady = true;
+    private static class TwilightListenerRecord implements Runnable {
+        private final TwilightListener mListener;
+        private final Handler mHandler;
 
-            IntentFilter filter = new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED);
-            filter.addAction(Intent.ACTION_TIME_CHANGED);
-            filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
-            filter.addAction(ACTION_UPDATE_TWILIGHT_STATE);
-            mContext.registerReceiver(mUpdateLocationReceiver, filter);
+        public TwilightListenerRecord(TwilightListener listener, Handler handler) {
+            mListener = listener;
+            mHandler = handler;
+        }
 
-            if (!mListeners.isEmpty()) {
-                mLocationHandler.enableLocationUpdates();
+        public void postUpdate() {
+            mHandler.post(this);
+        }
+
+        @Override
+        public void run() {
+            mListener.onTwilightStateChanged();
+        }
+
+    }
+
+    private final TwilightManager mService = new TwilightManager() {
+        /**
+         * Gets the current twilight state.
+         *
+         * @return The current twilight state, or null if no information is available.
+         */
+        @Override
+        public TwilightState getCurrentState() {
+            synchronized (mLock) {
+                return mTwilightState;
             }
         }
-    }
 
-    /**
-     * Gets the current twilight state.
-     *
-     * @return The current twilight state, or null if no information is available.
-     */
-    public TwilightState getCurrentState() {
-        synchronized (mLock) {
-            return mTwilightState;
-        }
-    }
+        /**
+         * Listens for twilight time.
+         *
+         * @param listener The listener.
+         */
+        @Override
+        public void registerListener(TwilightListener listener, Handler handler) {
+            synchronized (mLock) {
+                mListeners.add(new TwilightListenerRecord(listener, handler));
 
-    /**
-     * Listens for twilight time.
-     *
-     * @param listener The listener.
-     * @param handler The handler on which to post calls into the listener.
-     */
-    public void registerListener(TwilightListener listener, Handler handler) {
-        synchronized (mLock) {
-            mListeners.add(new TwilightListenerRecord(listener, handler));
-
-            if (mSystemReady && mListeners.size() == 1) {
-                mLocationHandler.enableLocationUpdates();
+                if (mListeners.size() == 1) {
+                    mLocationHandler.enableLocationUpdates();
+                }
             }
         }
-    }
+    };
 
     private void setTwilightState(TwilightState state) {
         synchronized (mLock) {
@@ -128,9 +143,10 @@
                 }
 
                 mTwilightState = state;
-                int count = mListeners.size();
-                for (int i = 0; i < count; i++) {
-                    mListeners.get(i).post();
+
+                final int listenerLen = mListeners.size();
+                for (int i = 0; i < listenerLen; i++) {
+                    mListeners.get(i).postUpdate();
                 }
             }
         }
@@ -162,124 +178,6 @@
         return distance >= totalAccuracy;
     }
 
-    /**
-     * Describes whether it is day or night.
-     * This object is immutable.
-     */
-    public static final class TwilightState {
-        private final boolean mIsNight;
-        private final long mYesterdaySunset;
-        private final long mTodaySunrise;
-        private final long mTodaySunset;
-        private final long mTomorrowSunrise;
-
-        TwilightState(boolean isNight,
-                long yesterdaySunset,
-                long todaySunrise, long todaySunset,
-                long tomorrowSunrise) {
-            mIsNight = isNight;
-            mYesterdaySunset = yesterdaySunset;
-            mTodaySunrise = todaySunrise;
-            mTodaySunset = todaySunset;
-            mTomorrowSunrise = tomorrowSunrise;
-        }
-
-        /**
-         * Returns true if it is currently night time.
-         */
-        public boolean isNight() {
-            return mIsNight;
-        }
-
-        /**
-         * Returns the time of yesterday's sunset in the System.currentTimeMillis() timebase,
-         * or -1 if the sun never sets.
-         */
-        public long getYesterdaySunset() {
-            return mYesterdaySunset;
-        }
-
-        /**
-         * Returns the time of today's sunrise in the System.currentTimeMillis() timebase,
-         * or -1 if the sun never rises.
-         */
-        public long getTodaySunrise() {
-            return mTodaySunrise;
-        }
-
-        /**
-         * Returns the time of today's sunset in the System.currentTimeMillis() timebase,
-         * or -1 if the sun never sets.
-         */
-        public long getTodaySunset() {
-            return mTodaySunset;
-        }
-
-        /**
-         * Returns the time of tomorrow's sunrise in the System.currentTimeMillis() timebase,
-         * or -1 if the sun never rises.
-         */
-        public long getTomorrowSunrise() {
-            return mTomorrowSunrise;
-        }
-
-        @Override
-        public boolean equals(Object o) {
-            return o instanceof TwilightState && equals((TwilightState)o);
-        }
-
-        public boolean equals(TwilightState other) {
-            return other != null
-                    && mIsNight == other.mIsNight
-                    && mYesterdaySunset == other.mYesterdaySunset
-                    && mTodaySunrise == other.mTodaySunrise
-                    && mTodaySunset == other.mTodaySunset
-                    && mTomorrowSunrise == other.mTomorrowSunrise;
-        }
-
-        @Override
-        public int hashCode() {
-            return 0; // don't care
-        }
-
-        @Override
-        public String toString() {
-            DateFormat f = DateFormat.getDateTimeInstance();
-            return "{TwilightState: isNight=" + mIsNight
-                    + ", mYesterdaySunset=" + f.format(new Date(mYesterdaySunset))
-                    + ", mTodaySunrise=" + f.format(new Date(mTodaySunrise))
-                    + ", mTodaySunset=" + f.format(new Date(mTodaySunset))
-                    + ", mTomorrowSunrise=" + f.format(new Date(mTomorrowSunrise))
-                    + "}";
-        }
-    }
-
-    /**
-     * Listener for changes in twilight state.
-     */
-    public interface TwilightListener {
-        public void onTwilightStateChanged();
-    }
-
-    private static final class TwilightListenerRecord implements Runnable {
-        private final TwilightListener mListener;
-        private final Handler mHandler;
-
-        public TwilightListenerRecord(TwilightListener listener, Handler handler) {
-            mListener = listener;
-            mHandler = handler;
-        }
-
-        public void post() {
-            mHandler.post(this);
-        }
-
-        @Override
-        public void run() {
-            mListener.onTwilightStateChanged();
-        }
-    }
-
     private final class LocationHandler extends Handler {
         private static final int MSG_ENABLE_LOCATION_UPDATES = 1;
         private static final int MSG_GET_NEW_LOCATION_UPDATE = 2;
@@ -518,11 +416,12 @@
             }
 
             Intent updateIntent = new Intent(ACTION_UPDATE_TWILIGHT_STATE);
-            PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0, updateIntent, 0);
+            PendingIntent pendingIntent = PendingIntent.getBroadcast(
+                    getContext(), 0, updateIntent, 0);
             mAlarmManager.cancel(pendingIntent);
             mAlarmManager.setExact(AlarmManager.RTC, nextUpdate, pendingIntent);
         }
-    };
+    }
 
     private final BroadcastReceiver mUpdateLocationReceiver = new BroadcastReceiver() {
         @Override
diff --git a/services/core/java/com/android/server/twilight/TwilightState.java b/services/core/java/com/android/server/twilight/TwilightState.java
new file mode 100644
index 0000000..91e24d7
--- /dev/null
+++ b/services/core/java/com/android/server/twilight/TwilightState.java
@@ -0,0 +1,112 @@
+/*
+ * 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.twilight;
+
+import java.text.DateFormat;
+import java.util.Date;
+
+/**
+ * Describes whether it is day or night.
+ * This object is immutable.
+ */
+public class TwilightState {
+    private final boolean mIsNight;
+    private final long mYesterdaySunset;
+    private final long mTodaySunrise;
+    private final long mTodaySunset;
+    private final long mTomorrowSunrise;
+
+    TwilightState(boolean isNight,
+            long yesterdaySunset,
+            long todaySunrise, long todaySunset,
+            long tomorrowSunrise) {
+        mIsNight = isNight;
+        mYesterdaySunset = yesterdaySunset;
+        mTodaySunrise = todaySunrise;
+        mTodaySunset = todaySunset;
+        mTomorrowSunrise = tomorrowSunrise;
+    }
+
+    /**
+     * Returns true if it is currently night time.
+     */
+    public boolean isNight() {
+        return mIsNight;
+    }
+
+    /**
+     * Returns the time of yesterday's sunset in the System.currentTimeMillis() timebase,
+     * or -1 if the sun never sets.
+     */
+    public long getYesterdaySunset() {
+        return mYesterdaySunset;
+    }
+
+    /**
+     * Returns the time of today's sunrise in the System.currentTimeMillis() timebase,
+     * or -1 if the sun never rises.
+     */
+    public long getTodaySunrise() {
+        return mTodaySunrise;
+    }
+
+    /**
+     * Returns the time of today's sunset in the System.currentTimeMillis() timebase,
+     * or -1 if the sun never sets.
+     */
+    public long getTodaySunset() {
+        return mTodaySunset;
+    }
+
+    /**
+     * Returns the time of tomorrow's sunrise in the System.currentTimeMillis() timebase,
+     * or -1 if the sun never rises.
+     */
+    public long getTomorrowSunrise() {
+        return mTomorrowSunrise;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        return o instanceof TwilightState && equals((TwilightState)o);
+    }
+
+    public boolean equals(TwilightState other) {
+        return other != null
+                && mIsNight == other.mIsNight
+                && mYesterdaySunset == other.mYesterdaySunset
+                && mTodaySunrise == other.mTodaySunrise
+                && mTodaySunset == other.mTodaySunset
+                && mTomorrowSunrise == other.mTomorrowSunrise;
+    }
+
+    @Override
+    public int hashCode() {
+        return 0; // don't care
+    }
+
+    @Override
+    public String toString() {
+        DateFormat f = DateFormat.getDateTimeInstance();
+        return "{TwilightState: isNight=" + mIsNight
+                + ", mYesterdaySunset=" + f.format(new Date(mYesterdaySunset))
+                + ", mTodaySunrise=" + f.format(new Date(mTodaySunrise))
+                + ", mTodaySunset=" + f.format(new Date(mTodaySunset))
+                + ", mTomorrowSunrise=" + f.format(new Date(mTomorrowSunrise))
+                + "}";
+    }
+}
diff --git a/services/java/com/android/server/updates/CarrierProvisioningUrlsInstallReceiver.java b/services/core/java/com/android/server/updates/CarrierProvisioningUrlsInstallReceiver.java
similarity index 100%
rename from services/java/com/android/server/updates/CarrierProvisioningUrlsInstallReceiver.java
rename to services/core/java/com/android/server/updates/CarrierProvisioningUrlsInstallReceiver.java
diff --git a/services/java/com/android/server/updates/CertPinInstallReceiver.java b/services/core/java/com/android/server/updates/CertPinInstallReceiver.java
similarity index 100%
rename from services/java/com/android/server/updates/CertPinInstallReceiver.java
rename to services/core/java/com/android/server/updates/CertPinInstallReceiver.java
diff --git a/services/java/com/android/server/updates/ConfigUpdateInstallReceiver.java b/services/core/java/com/android/server/updates/ConfigUpdateInstallReceiver.java
similarity index 100%
rename from services/java/com/android/server/updates/ConfigUpdateInstallReceiver.java
rename to services/core/java/com/android/server/updates/ConfigUpdateInstallReceiver.java
diff --git a/services/java/com/android/server/updates/IntentFirewallInstallReceiver.java b/services/core/java/com/android/server/updates/IntentFirewallInstallReceiver.java
similarity index 100%
rename from services/java/com/android/server/updates/IntentFirewallInstallReceiver.java
rename to services/core/java/com/android/server/updates/IntentFirewallInstallReceiver.java
diff --git a/services/java/com/android/server/updates/SELinuxPolicyInstallReceiver.java b/services/core/java/com/android/server/updates/SELinuxPolicyInstallReceiver.java
similarity index 100%
rename from services/java/com/android/server/updates/SELinuxPolicyInstallReceiver.java
rename to services/core/java/com/android/server/updates/SELinuxPolicyInstallReceiver.java
diff --git a/services/java/com/android/server/updates/SmsShortCodesInstallReceiver.java b/services/core/java/com/android/server/updates/SmsShortCodesInstallReceiver.java
similarity index 100%
rename from services/java/com/android/server/updates/SmsShortCodesInstallReceiver.java
rename to services/core/java/com/android/server/updates/SmsShortCodesInstallReceiver.java
diff --git a/services/java/com/android/server/updates/TZInfoInstallReceiver.java b/services/core/java/com/android/server/updates/TZInfoInstallReceiver.java
similarity index 100%
rename from services/java/com/android/server/updates/TZInfoInstallReceiver.java
rename to services/core/java/com/android/server/updates/TZInfoInstallReceiver.java
diff --git a/services/java/com/android/server/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
similarity index 98%
rename from services/java/com/android/server/WallpaperManagerService.java
rename to services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index e6b6b93..97ea52c 100644
--- a/services/java/com/android/server/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server;
+package com.android.server.wallpaper;
 
 import static android.os.ParcelFileDescriptor.*;
 
@@ -85,8 +85,8 @@
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.JournaledFile;
 
-class WallpaperManagerService extends IWallpaperManager.Stub {
-    static final String TAG = "WallpaperService";
+public class WallpaperManagerService extends IWallpaperManager.Stub {
+    static final String TAG = "WallpaperManagerService";
     static final boolean DEBUG = false;
 
     final Object mLock = new Object[0];
@@ -98,7 +98,6 @@
     static final long MIN_WALLPAPER_CRASH_TIME = 10000;
     static final String WALLPAPER = "wallpaper";
     static final String WALLPAPER_INFO = "wallpaper_info.xml";
-
     /**
      * Name of the component used to display bitmap wallpapers from either the gallery or
      * built-in wallpapers.
@@ -505,7 +504,12 @@
         }
     }
 
-    String getName() {
+    /** Called by SystemBackupAgent */
+    public String getName() {
+        // Verify caller is the system
+        if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) {
+            throw new RuntimeException("getName() can only be called from the system process");
+        }
         synchronized (mLock) {
             return mWallpaperMap.get(0).name;
         }
@@ -1175,7 +1179,11 @@
     }
 
     // Called by SystemBackupAgent after files are restored to disk.
-    void settingsRestored() {
+    public void settingsRestored() {
+        // Verify caller is the system
+        if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) {
+            throw new RuntimeException("settingsRestored() can only be called from the system process");
+        }
         // TODO: If necessary, make it work for secondary users as well. This currently assumes
         // restores only to the primary user
         if (DEBUG) Slog.v(TAG, "settingsRestored");
diff --git a/services/java/com/android/server/wifi/README.txt b/services/core/java/com/android/server/wifi/README.txt
similarity index 100%
rename from services/java/com/android/server/wifi/README.txt
rename to services/core/java/com/android/server/wifi/README.txt
diff --git a/services/java/com/android/server/wifi/WifiController.java b/services/core/java/com/android/server/wifi/WifiController.java
similarity index 100%
rename from services/java/com/android/server/wifi/WifiController.java
rename to services/core/java/com/android/server/wifi/WifiController.java
diff --git a/services/java/com/android/server/wifi/WifiNotificationController.java b/services/core/java/com/android/server/wifi/WifiNotificationController.java
similarity index 100%
rename from services/java/com/android/server/wifi/WifiNotificationController.java
rename to services/core/java/com/android/server/wifi/WifiNotificationController.java
diff --git a/services/java/com/android/server/wifi/WifiService.java b/services/core/java/com/android/server/wifi/WifiService.java
similarity index 100%
rename from services/java/com/android/server/wifi/WifiService.java
rename to services/core/java/com/android/server/wifi/WifiService.java
diff --git a/services/java/com/android/server/wifi/WifiSettingsStore.java b/services/core/java/com/android/server/wifi/WifiSettingsStore.java
similarity index 100%
rename from services/java/com/android/server/wifi/WifiSettingsStore.java
rename to services/core/java/com/android/server/wifi/WifiSettingsStore.java
diff --git a/services/java/com/android/server/wifi/WifiTrafficPoller.java b/services/core/java/com/android/server/wifi/WifiTrafficPoller.java
similarity index 100%
rename from services/java/com/android/server/wifi/WifiTrafficPoller.java
rename to services/core/java/com/android/server/wifi/WifiTrafficPoller.java
diff --git a/services/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
similarity index 100%
rename from services/java/com/android/server/wm/AppTransition.java
rename to services/core/java/com/android/server/wm/AppTransition.java
diff --git a/services/java/com/android/server/wm/AppWindowAnimator.java b/services/core/java/com/android/server/wm/AppWindowAnimator.java
similarity index 95%
rename from services/java/com/android/server/wm/AppWindowAnimator.java
rename to services/core/java/com/android/server/wm/AppWindowAnimator.java
index 3cccf1d..7fe895b 100644
--- a/services/java/com/android/server/wm/AppWindowAnimator.java
+++ b/services/core/java/com/android/server/wm/AppWindowAnimator.java
@@ -1,4 +1,18 @@
-// Copyright 2012 Google Inc. All Rights Reserved.
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 
 package com.android.server.wm;
 
diff --git a/services/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
similarity index 99%
rename from services/java/com/android/server/wm/AppWindowToken.java
rename to services/core/java/com/android/server/wm/AppWindowToken.java
index e98014b..ca4ad8a 100644
--- a/services/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -105,6 +105,8 @@
     // Input application handle used by the input dispatcher.
     final InputApplicationHandle mInputApplicationHandle;
 
+    boolean mDeferRemoval;
+
     AppWindowToken(WindowManagerService _service, IApplicationToken _token) {
         super(_service, _token.asBinder(),
                 WindowManager.LayoutParams.TYPE_APPLICATION, true);
diff --git a/services/java/com/android/server/wm/BlackFrame.java b/services/core/java/com/android/server/wm/BlackFrame.java
similarity index 100%
rename from services/java/com/android/server/wm/BlackFrame.java
rename to services/core/java/com/android/server/wm/BlackFrame.java
diff --git a/services/core/java/com/android/server/wm/CircularDisplayMask.java b/services/core/java/com/android/server/wm/CircularDisplayMask.java
new file mode 100644
index 0000000..35d19c1
--- /dev/null
+++ b/services/core/java/com/android/server/wm/CircularDisplayMask.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.view.Display;
+import android.view.Surface;
+import android.view.Surface.OutOfResourcesException;
+import android.view.SurfaceControl;
+import android.view.SurfaceSession;
+
+class CircularDisplayMask {
+    private static final String TAG = "CircularDisplayMask";
+
+    private static final int STROKE_WIDTH = 2;
+
+    private final SurfaceControl mSurfaceControl;
+    private final Surface mSurface = new Surface();
+    private int mLastDW;
+    private int mLastDH;
+    private boolean mDrawNeeded;
+    private Paint mPaint;
+    private int mRotation;
+
+    public CircularDisplayMask(Display display, SurfaceSession session, int zOrder) {
+        SurfaceControl ctrl = null;
+        try {
+            ctrl = new SurfaceControl(session, "CircularDisplayMask",
+                320, 290, PixelFormat.TRANSLUCENT, SurfaceControl.HIDDEN);
+            ctrl.setLayerStack(display.getLayerStack());
+            ctrl.setLayer(zOrder);
+            ctrl.setPosition(0, 0);
+            ctrl.show();
+            mSurface.copyFrom(ctrl);
+        } catch (OutOfResourcesException e) {
+        }
+        mSurfaceControl = ctrl;
+        mDrawNeeded = true;
+        mPaint = new Paint();
+        mPaint.setAntiAlias(true);
+        mPaint.setStyle(Paint.Style.STROKE);
+        mPaint.setColor(Color.BLACK);
+        mPaint.setStrokeWidth(STROKE_WIDTH);
+    }
+
+    private void drawIfNeeded() {
+        if (!mDrawNeeded) {
+            return;
+        }
+        mDrawNeeded = false;
+
+        Rect dirty = new Rect(0, 0, mLastDW, mLastDH);
+        Canvas c = null;
+        try {
+            c = mSurface.lockCanvas(dirty);
+        } catch (IllegalArgumentException e) {
+        } catch (Surface.OutOfResourcesException e) {
+        }
+        if (c == null) {
+            return;
+        }
+        int cx = 160;
+        int cy = 160;
+        switch (mRotation) {
+            case Surface.ROTATION_0:
+            case Surface.ROTATION_90:
+                // chin bottom or right
+                cx = 160;
+                cy = 160;
+                break;
+            case Surface.ROTATION_180:
+                // chin top
+                cx = 160;
+                cy = 145;
+                break;
+            case Surface.ROTATION_270:
+                cx = 145;
+                cy = 160;
+                break;
+        }
+        c.drawCircle(cx, cy, 160, mPaint);
+
+        mSurface.unlockCanvasAndPost(c);
+    }
+
+    // Note: caller responsible for being inside
+    // Surface.openTransaction() / closeTransaction()
+    public void setVisibility(boolean on) {
+        if (mSurfaceControl == null) {
+            return;
+        }
+        drawIfNeeded();
+        if (on) {
+            mSurfaceControl.show();
+        } else {
+            mSurfaceControl.hide();
+        }
+    }
+
+    void positionSurface(int dw, int dh, int rotation) {
+        if (mLastDW == dw && mLastDH == dh) {
+            return;
+        }
+        mLastDW = dw;
+        mLastDH = dh;
+        mSurfaceControl.setSize(dw, dh);
+        mDrawNeeded = true;
+        mRotation = rotation;
+    }
+
+}
diff --git a/services/java/com/android/server/wm/DimLayer.java b/services/core/java/com/android/server/wm/DimLayer.java
similarity index 83%
rename from services/java/com/android/server/wm/DimLayer.java
rename to services/core/java/com/android/server/wm/DimLayer.java
index c189ddd..c09ea5c 100644
--- a/services/java/com/android/server/wm/DimLayer.java
+++ b/services/core/java/com/android/server/wm/DimLayer.java
@@ -1,4 +1,18 @@
-// Copyright 2012 Google Inc. All Rights Reserved.
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 
 package com.android.server.wm;
 
@@ -51,9 +65,9 @@
     /** Owning stack */
     final TaskStack mStack;
 
-    DimLayer(WindowManagerService service, TaskStack stack) {
+    DimLayer(WindowManagerService service, TaskStack stack, DisplayContent displayContent) {
         mStack = stack;
-        mDisplayContent = stack.getDisplayContent();
+        mDisplayContent = displayContent;
         final int displayId = mDisplayContent.getDisplayId();
         if (DEBUG) Slog.v(TAG, "Ctor: displayId=" + displayId);
         SurfaceControl.openTransaction();
@@ -125,8 +139,54 @@
         }
     }
 
+    /**
+     * @param layer The new layer value.
+     * @param inTransaction Whether the call is made within a surface transaction.
+     */
+    void adjustSurface(int layer, boolean inTransaction) {
+        final int dw, dh;
+        final float xPos, yPos;
+        if (!mStack.isFullscreen()) {
+            dw = mBounds.width();
+            dh = mBounds.height();
+            xPos = mBounds.left;
+            yPos = mBounds.top;
+        } else {
+            // Set surface size to screen size.
+            final DisplayInfo info = mDisplayContent.getDisplayInfo();
+            // Multiply by 1.5 so that rotating a frozen surface that includes this does not expose
+            // a corner.
+            dw = (int) (info.logicalWidth * 1.5);
+            dh = (int) (info.logicalHeight * 1.5);
+            // back off position so 1/4 of Surface is before and 1/4 is after.
+            xPos = -1 * dw / 6;
+            yPos = -1 * dh / 6;
+        }
+
+        try {
+            if (!inTransaction) {
+                SurfaceControl.openTransaction();
+            }
+            mDimSurface.setPosition(xPos, yPos);
+            mDimSurface.setSize(dw, dh);
+            mDimSurface.setLayer(layer);
+        } catch (RuntimeException e) {
+            Slog.w(TAG, "Failure setting size or layer", e);
+        } finally {
+            if (!inTransaction) {
+                SurfaceControl.closeTransaction();
+            }
+        }
+        mLastBounds.set(mBounds);
+        mLayer = layer;
+    }
+
+    // Assumes that surface transactions are currently closed.
     void setBounds(Rect bounds) {
         mBounds.set(bounds);
+        if (isDimming() && !mLastBounds.equals(bounds)) {
+            adjustSurface(mLayer, false);
+        }
     }
 
     /**
@@ -164,35 +224,8 @@
             return;
         }
 
-        final int dw, dh;
-        final float xPos, yPos;
-        if (mStack.hasSibling()) {
-            dw = mBounds.width();
-            dh = mBounds.height();
-            xPos = mBounds.left;
-            yPos = mBounds.right;
-        } else {
-            // Set surface size to screen size.
-            final DisplayInfo info = mDisplayContent.getDisplayInfo();
-            // Multiply by 1.5 so that rotating a frozen surface that includes this does not expose a
-            // corner.
-            dw = (int) (info.logicalWidth * 1.5);
-            dh = (int) (info.logicalHeight * 1.5);
-            // back off position so 1/4 of Surface is before and 1/4 is after.
-            xPos = -1 * dw / 6;
-            yPos = -1 * dh / 6;
-        }
-
         if (!mLastBounds.equals(mBounds) || mLayer != layer) {
-            try {
-                mDimSurface.setPosition(xPos, yPos);
-                mDimSurface.setSize(dw, dh);
-                mDimSurface.setLayer(layer);
-            } catch (RuntimeException e) {
-                Slog.w(TAG, "Failure setting size or layer", e);
-            }
-            mLastBounds.set(mBounds);
-            mLayer = layer;
+            adjustSurface(layer, true);
         }
 
         long curTime = SystemClock.uptimeMillis();
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
new file mode 100644
index 0000000..d4bcd5c
--- /dev/null
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -0,0 +1,415 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID;
+import static com.android.server.wm.WindowManagerService.DEBUG_VISIBILITY;
+import static com.android.server.wm.WindowManagerService.TAG;
+
+import android.graphics.Rect;
+import android.graphics.Region;
+import android.util.Slog;
+import android.view.Display;
+import android.view.DisplayInfo;
+import android.view.Surface;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+
+class DisplayContentList extends ArrayList<DisplayContent> {
+}
+
+/**
+ * Utility class for keeping track of the WindowStates and other pertinent contents of a
+ * particular Display.
+ *
+ * IMPORTANT: No method from this class should ever be used without holding
+ * WindowManagerService.mWindowMap.
+ */
+class DisplayContent {
+
+    /** Unique identifier of this stack. */
+    private final int mDisplayId;
+
+    /** Z-ordered (bottom-most first) list of all Window objects. Assigned to an element
+     * from mDisplayWindows; */
+    private final WindowList mWindows = new WindowList();
+
+    // This protects the following display size properties, so that
+    // getDisplaySize() doesn't need to acquire the global lock.  This is
+    // needed because the window manager sometimes needs to use ActivityThread
+    // while it has its global state locked (for example to load animation
+    // resources), but the ActivityThread also needs get the current display
+    // size sometimes when it has its package lock held.
+    //
+    // These will only be modified with both mWindowMap and mDisplaySizeLock
+    // held (in that order) so the window manager doesn't need to acquire this
+    // lock when needing these values in its normal operation.
+    final Object mDisplaySizeLock = new Object();
+    int mInitialDisplayWidth = 0;
+    int mInitialDisplayHeight = 0;
+    int mInitialDisplayDensity = 0;
+    int mBaseDisplayWidth = 0;
+    int mBaseDisplayHeight = 0;
+    int mBaseDisplayDensity = 0;
+    private final DisplayInfo mDisplayInfo = new DisplayInfo();
+    private final Display mDisplay;
+
+    Rect mBaseDisplayRect = new Rect();
+    Rect mContentRect = new Rect();
+
+    // Accessed directly by all users.
+    boolean layoutNeeded;
+    int pendingLayoutChanges;
+    final boolean isDefaultDisplay;
+
+    /** Window tokens that are in the process of exiting, but still on screen for animations. */
+    final ArrayList<WindowToken> mExitingTokens = new ArrayList<WindowToken>();
+
+    /** Array containing all TaskStacks on this display.  Array
+     * is stored in display order with the current bottom stack at 0. */
+    private final ArrayList<TaskStack> mStacks = new ArrayList<TaskStack>();
+
+    /** A special TaskStack with id==HOME_STACK_ID that moves to the bottom whenever any TaskStack
+     * (except a future lockscreen TaskStack) moves to the top. */
+    private TaskStack mHomeStack = null;
+
+    /** Detect user tapping outside of current focused stack bounds .*/
+    StackTapPointerEventListener mTapDetector;
+
+    /** Detect user tapping outside of current focused stack bounds .*/
+    Region mTouchExcludeRegion = new Region();
+
+    /** Save allocating when calculating rects */
+    Rect mTmpRect = new Rect();
+
+    /** For gathering Task objects in order. */
+    final ArrayList<Task> mTmpTaskHistory = new ArrayList<Task>();
+
+    final WindowManagerService mService;
+
+    /** Remove this display when animation on it has completed. */
+    boolean mDeferredRemoval;
+
+    /**
+     * @param display May not be null.
+     * @param service You know.
+     */
+    DisplayContent(Display display, WindowManagerService service) {
+        mDisplay = display;
+        mDisplayId = display.getDisplayId();
+        display.getDisplayInfo(mDisplayInfo);
+        isDefaultDisplay = mDisplayId == Display.DEFAULT_DISPLAY;
+        mService = service;
+    }
+
+    int getDisplayId() {
+        return mDisplayId;
+    }
+
+    WindowList getWindowList() {
+        return mWindows;
+    }
+
+    Display getDisplay() {
+        return mDisplay;
+    }
+
+    DisplayInfo getDisplayInfo() {
+        return mDisplayInfo;
+    }
+
+    /**
+     * Returns true if the specified UID has access to this display.
+     */
+    public boolean hasAccess(int uid) {
+        return mDisplay.hasAccess(uid);
+    }
+
+    public boolean isPrivate() {
+        return (mDisplay.getFlags() & Display.FLAG_PRIVATE) != 0;
+    }
+
+    ArrayList<TaskStack> getStacks() {
+        return mStacks;
+    }
+
+    /**
+     * Retrieve the tasks on this display in stack order from the bottommost TaskStack up.
+     * @return All the Tasks, in order, on this display.
+     */
+    ArrayList<Task> getTasks() {
+        mTmpTaskHistory.clear();
+        final int numStacks = mStacks.size();
+        for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
+            mTmpTaskHistory.addAll(mStacks.get(stackNdx).getTasks());
+        }
+        return mTmpTaskHistory;
+    }
+
+    TaskStack getHomeStack() {
+        if (mHomeStack == null) {
+            Slog.e(TAG, "getHomeStack: Returning null from this=" + this);
+        }
+        return mHomeStack;
+    }
+
+    void updateDisplayInfo() {
+        mDisplay.getDisplayInfo(mDisplayInfo);
+        for (int i = mStacks.size() - 1; i >= 0; --i) {
+            mStacks.get(i).updateDisplayInfo();
+        }
+    }
+
+    void getLogicalDisplayRect(Rect out) {
+        // Uses same calculation as in LogicalDisplay#configureDisplayInTransactionLocked.
+        final int orientation = mDisplayInfo.rotation;
+        boolean rotated = (orientation == Surface.ROTATION_90
+                || orientation == Surface.ROTATION_270);
+        final int physWidth = rotated ? mBaseDisplayHeight : mBaseDisplayWidth;
+        final int physHeight = rotated ? mBaseDisplayWidth : mBaseDisplayHeight;
+        int width = mDisplayInfo.logicalWidth;
+        int left = (physWidth - width) / 2;
+        int height = mDisplayInfo.logicalHeight;
+        int top = (physHeight - height) / 2;
+        out.set(left, top, left + width, top + height);
+    }
+
+    /** Refer to {@link WindowManagerService#attachStack(int, int)} */
+    void attachStack(TaskStack stack) {
+        if (stack.mStackId == HOME_STACK_ID) {
+            if (mHomeStack != null) {
+                throw new IllegalArgumentException("attachStack: HOME_STACK_ID (0) not first.");
+            }
+            mHomeStack = stack;
+        }
+        mStacks.add(stack);
+        layoutNeeded = true;
+    }
+
+    void moveStack(TaskStack stack, boolean toTop) {
+        mStacks.remove(stack);
+        mStacks.add(toTop ? mStacks.size() : 0, stack);
+    }
+
+    void detachStack(TaskStack stack) {
+        mStacks.remove(stack);
+    }
+
+    /**
+     * Propagate the new bounds to all child stacks.
+     * @param contentRect The bounds to apply at the top level.
+     */
+    void resize(Rect contentRect) {
+        mContentRect.set(contentRect);
+    }
+
+    int stackIdFromPoint(int x, int y) {
+        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+            final TaskStack stack = mStacks.get(stackNdx);
+            stack.getBounds(mTmpRect);
+            if (mTmpRect.contains(x, y)) {
+                return stack.mStackId;
+            }
+        }
+        return -1;
+    }
+
+    void setTouchExcludeRegion(TaskStack focusedStack) {
+        mTouchExcludeRegion.set(mBaseDisplayRect);
+        WindowList windows = getWindowList();
+        for (int i = windows.size() - 1; i >= 0; --i) {
+            final WindowState win = windows.get(i);
+            final TaskStack stack = win.getStack();
+            if (win.isVisibleLw() && stack != null && stack != focusedStack) {
+                mTmpRect.set(win.mVisibleFrame);
+                mTmpRect.intersect(win.mVisibleInsets);
+                mTouchExcludeRegion.op(mTmpRect, Region.Op.DIFFERENCE);
+            }
+        }
+    }
+
+    void switchUserStacks(int newUserId) {
+        final WindowList windows = getWindowList();
+        for (int i = 0; i < windows.size(); i++) {
+            final WindowState win = windows.get(i);
+            if (win.isHiddenFromUserLocked()) {
+                if (DEBUG_VISIBILITY) Slog.w(TAG, "user changing " + newUserId + " hiding "
+                        + win + ", attrs=" + win.mAttrs.type + ", belonging to "
+                        + win.mOwnerUid);
+                win.hideLw(false);
+            }
+        }
+
+        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+            mStacks.get(stackNdx).switchUser(newUserId);
+        }
+    }
+
+    void resetAnimationBackgroundAnimator() {
+        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+            mStacks.get(stackNdx).resetAnimationBackgroundAnimator();
+        }
+    }
+
+    boolean animateDimLayers() {
+        boolean result = false;
+        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+            result |= mStacks.get(stackNdx).animateDimLayers();
+        }
+        return result;
+    }
+
+    void resetDimming() {
+        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+            mStacks.get(stackNdx).resetDimmingTag();
+        }
+    }
+
+    boolean isDimming() {
+        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+            if (mStacks.get(stackNdx).isDimming()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    void stopDimmingIfNeeded() {
+        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+            mStacks.get(stackNdx).stopDimmingIfNeeded();
+        }
+    }
+
+    void close() {
+        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+            mStacks.get(stackNdx).close();
+        }
+    }
+
+    boolean isAnimating() {
+        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+            final TaskStack stack = mStacks.get(stackNdx);
+            if (stack.isAnimating()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    void checkForDeferredActions() {
+        boolean animating = false;
+        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+            final TaskStack stack = mStacks.get(stackNdx);
+            if (stack.isAnimating()) {
+                animating = true;
+            } else {
+                if (stack.mDeferDetach) {
+                    mService.detachStackLocked(this, stack);
+                }
+                final ArrayList<Task> tasks = stack.getTasks();
+                for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
+                    final Task task = tasks.get(taskNdx);
+                    AppTokenList tokens = task.mAppTokens;
+                    for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
+                        AppWindowToken wtoken = tokens.get(tokenNdx);
+                        if (wtoken.mDeferRemoval) {
+                            wtoken.mDeferRemoval = false;
+                            mService.removeAppFromTaskLocked(wtoken);
+                        }
+                    }
+                    if (task.mDeferRemoval) {
+                        task.mDeferRemoval = false;
+                        mService.removeTaskLocked(task);
+                    }
+                }
+            }
+        }
+        if (!animating && mDeferredRemoval) {
+            mService.onDisplayRemoved(mDisplayId);
+        }
+    }
+
+    public void dump(String prefix, PrintWriter pw) {
+        pw.print(prefix); pw.print("Display: mDisplayId="); pw.println(mDisplayId);
+        final String subPrefix = "  " + prefix;
+        pw.print(subPrefix); pw.print("init="); pw.print(mInitialDisplayWidth); pw.print("x");
+            pw.print(mInitialDisplayHeight); pw.print(" "); pw.print(mInitialDisplayDensity);
+            pw.print("dpi");
+            if (mInitialDisplayWidth != mBaseDisplayWidth
+                    || mInitialDisplayHeight != mBaseDisplayHeight
+                    || mInitialDisplayDensity != mBaseDisplayDensity) {
+                pw.print(" base=");
+                pw.print(mBaseDisplayWidth); pw.print("x"); pw.print(mBaseDisplayHeight);
+                pw.print(" "); pw.print(mBaseDisplayDensity); pw.print("dpi");
+            }
+            pw.print(" cur=");
+            pw.print(mDisplayInfo.logicalWidth);
+            pw.print("x"); pw.print(mDisplayInfo.logicalHeight);
+            pw.print(" app=");
+            pw.print(mDisplayInfo.appWidth);
+            pw.print("x"); pw.print(mDisplayInfo.appHeight);
+            pw.print(" rng="); pw.print(mDisplayInfo.smallestNominalAppWidth);
+            pw.print("x"); pw.print(mDisplayInfo.smallestNominalAppHeight);
+            pw.print("-"); pw.print(mDisplayInfo.largestNominalAppWidth);
+            pw.print("x"); pw.println(mDisplayInfo.largestNominalAppHeight);
+            pw.print(subPrefix); pw.print("deferred="); pw.print(mDeferredRemoval);
+                pw.print(" layoutNeeded="); pw.println(layoutNeeded);
+        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+            final TaskStack stack = mStacks.get(stackNdx);
+            pw.print(prefix); pw.print("mStacks[" + stackNdx + "]"); pw.println(stack.mStackId);
+            stack.dump(prefix + "  ", pw);
+        }
+        pw.println();
+        pw.println("  Application tokens in bottom up Z order:");
+        int ndx = 0;
+        final int numStacks = mStacks.size();
+        for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
+            ArrayList<Task> tasks = mStacks.get(stackNdx).getTasks();
+            for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
+                AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
+                for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
+                    final AppWindowToken wtoken = tokens.get(tokenNdx);
+                    pw.print("  App #"); pw.print(ndx++);
+                            pw.print(' '); pw.print(wtoken); pw.println(":");
+                    wtoken.dump(pw, "    ");
+                }
+            }
+        }
+        if (ndx == 0) {
+            pw.println("    None");
+        }
+        pw.println();
+        if (!mExitingTokens.isEmpty()) {
+            pw.println();
+            pw.println("  Exiting tokens:");
+            for (int i=mExitingTokens.size()-1; i>=0; i--) {
+                WindowToken token = mExitingTokens.get(i);
+                pw.print("  Exiting #"); pw.print(i);
+                pw.print(' '); pw.print(token);
+                pw.println(':');
+                token.dump(pw, "    ");
+            }
+        }
+        pw.println();
+    }
+
+    @Override
+    public String toString() {
+        return "Display " + mDisplayId + " info=" + mDisplayInfo + " stacks=" + mStacks;
+    }
+}
diff --git a/services/java/com/android/server/wm/DisplayMagnifier.java b/services/core/java/com/android/server/wm/DisplayMagnifier.java
similarity index 100%
rename from services/java/com/android/server/wm/DisplayMagnifier.java
rename to services/core/java/com/android/server/wm/DisplayMagnifier.java
diff --git a/services/java/com/android/server/wm/DisplaySettings.java b/services/core/java/com/android/server/wm/DisplaySettings.java
similarity index 100%
rename from services/java/com/android/server/wm/DisplaySettings.java
rename to services/core/java/com/android/server/wm/DisplaySettings.java
diff --git a/services/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
similarity index 100%
rename from services/java/com/android/server/wm/DragState.java
rename to services/core/java/com/android/server/wm/DragState.java
diff --git a/services/java/com/android/server/wm/FakeWindowImpl.java b/services/core/java/com/android/server/wm/FakeWindowImpl.java
similarity index 100%
rename from services/java/com/android/server/wm/FakeWindowImpl.java
rename to services/core/java/com/android/server/wm/FakeWindowImpl.java
diff --git a/services/java/com/android/server/wm/FocusedStackFrame.java b/services/core/java/com/android/server/wm/FocusedStackFrame.java
similarity index 97%
rename from services/java/com/android/server/wm/FocusedStackFrame.java
rename to services/core/java/com/android/server/wm/FocusedStackFrame.java
index cc48b86..f1f5fe8 100644
--- a/services/java/com/android/server/wm/FocusedStackFrame.java
+++ b/services/core/java/com/android/server/wm/FocusedStackFrame.java
@@ -41,7 +41,7 @@
     private final SurfaceControl mSurfaceControl;
     private final Surface mSurface = new Surface();
     private final Rect mLastBounds = new Rect();
-    private final Rect mBounds = new Rect();
+    final Rect mBounds = new Rect();
     private final Rect mTmpDrawRect = new Rect();
 
     public FocusedStackFrame(Display display, SurfaceSession session) {
@@ -131,9 +131,9 @@
         }
     }
 
-    public void setBounds(Rect bounds) {
-        if (false && DEBUG_STACK) Slog.i(TAG, "setBounds: bounds=" + bounds);
-        mBounds.set(bounds);
+    public void setBounds(TaskStack stack) {
+        stack.getBounds(mBounds);
+        if (false && DEBUG_STACK) Slog.i(TAG, "setBounds: bounds=" + mBounds);
     }
 
     public void setLayer(int layer) {
diff --git a/services/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
similarity index 97%
rename from services/java/com/android/server/wm/InputMonitor.java
rename to services/core/java/com/android/server/wm/InputMonitor.java
index 3d2ec45..b27c8d6 100644
--- a/services/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -58,6 +58,8 @@
     private final Object mInputDevicesReadyMonitor = new Object();
     private boolean mInputDevicesReady;
 
+    Rect mTmpRect = new Rect();
+
     public InputMonitor(WindowManagerService service) {
         mService = service;
     }
@@ -175,7 +177,8 @@
         if (modal && child.mAppToken != null) {
             // Limit the outer touch to the activity stack region.
             flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
-            inputWindowHandle.touchableRegion.set(child.getStackBounds());
+            child.getStackBounds(mTmpRect);
+            inputWindowHandle.touchableRegion.set(mTmpRect);
         } else {
             // Not modal or full screen modal
             child.getTouchableRegion(inputWindowHandle.touchableRegion);
@@ -352,17 +355,16 @@
     /* Provides an opportunity for the window manager policy to intercept early key
      * processing as soon as the key has been read from the device. */
     @Override
-    public int interceptKeyBeforeQueueing(
-            KeyEvent event, int policyFlags, boolean isScreenOn) {
-        return mService.mPolicy.interceptKeyBeforeQueueing(event, policyFlags, isScreenOn);
+    public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
+        return mService.mPolicy.interceptKeyBeforeQueueing(event, policyFlags);
     }
 
     /* Provides an opportunity for the window manager policy to intercept early
      * motion event processing when the screen is off since these events are normally
      * dropped. */
     @Override
-    public int interceptMotionBeforeQueueingWhenScreenOff(int policyFlags) {
-        return mService.mPolicy.interceptMotionBeforeQueueingWhenScreenOff(policyFlags);
+    public int interceptWakeMotionBeforeQueueing(long whenNanos, int policyFlags) {
+        return mService.mPolicy.interceptWakeMotionBeforeQueueing(whenNanos, policyFlags);
     }
 
     /* Provides an opportunity for the window manager policy to process a key before
diff --git a/services/java/com/android/server/wm/KeyguardDisableHandler.java b/services/core/java/com/android/server/wm/KeyguardDisableHandler.java
similarity index 100%
rename from services/java/com/android/server/wm/KeyguardDisableHandler.java
rename to services/core/java/com/android/server/wm/KeyguardDisableHandler.java
diff --git a/services/java/com/android/server/wm/PointerEventDispatcher.java b/services/core/java/com/android/server/wm/PointerEventDispatcher.java
similarity index 100%
rename from services/java/com/android/server/wm/PointerEventDispatcher.java
rename to services/core/java/com/android/server/wm/PointerEventDispatcher.java
diff --git a/services/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
similarity index 100%
rename from services/java/com/android/server/wm/ScreenRotationAnimation.java
rename to services/core/java/com/android/server/wm/ScreenRotationAnimation.java
diff --git a/services/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
similarity index 98%
rename from services/java/com/android/server/wm/Session.java
rename to services/core/java/com/android/server/wm/Session.java
index 87cabc9..ca9076f 100644
--- a/services/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -293,7 +293,11 @@
             // !!! FIXME: put all this heavy stuff onto the mH looper, as well as
             // the actual drag event dispatch stuff in the dragstate
 
-            Display display = callingWin.mDisplayContent.getDisplay();
+            final DisplayContent displayContent = callingWin.getDisplayContent();
+            if (displayContent == null) {
+               return false;
+            }
+            Display display = displayContent.getDisplay();
             mService.mDragState.register(display);
             mService.mInputMonitor.updateInputWindowsLw(true /*force*/);
             if (!mService.mInputManager.transferTouchFocus(callingWin.mInputChannel,
diff --git a/services/java/com/android/server/wm/StackTapPointerEventListener.java b/services/core/java/com/android/server/wm/StackTapPointerEventListener.java
similarity index 100%
rename from services/java/com/android/server/wm/StackTapPointerEventListener.java
rename to services/core/java/com/android/server/wm/StackTapPointerEventListener.java
diff --git a/services/java/com/android/server/wm/StartingData.java b/services/core/java/com/android/server/wm/StartingData.java
similarity index 100%
rename from services/java/com/android/server/wm/StartingData.java
rename to services/core/java/com/android/server/wm/StartingData.java
diff --git a/services/java/com/android/server/wm/StrictModeFlash.java b/services/core/java/com/android/server/wm/StrictModeFlash.java
similarity index 100%
rename from services/java/com/android/server/wm/StrictModeFlash.java
rename to services/core/java/com/android/server/wm/StrictModeFlash.java
diff --git a/services/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
similarity index 73%
rename from services/java/com/android/server/wm/Task.java
rename to services/core/java/com/android/server/wm/Task.java
index 13fdbc8..09c4e20 100644
--- a/services/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -16,15 +16,17 @@
 
 package com.android.server.wm;
 
+import static com.android.server.wm.WindowManagerService.TAG;
+
 import android.util.EventLog;
-import com.android.server.EventLogTags;
+import android.util.Slog;
 
 class Task {
-//    private final String TAG = "TaskGroup";
     TaskStack mStack;
     final AppTokenList mAppTokens = new AppTokenList();
     final int taskId;
     final int mUserId;
+    boolean mDeferRemoval = false;
 
     Task(AppWindowToken wtoken, TaskStack stack, int userId) {
         taskId = wtoken.groupId;
@@ -38,18 +40,24 @@
     }
 
     void addAppToken(int addPos, AppWindowToken wtoken) {
+        final int lastPos = mAppTokens.size();
+        if (addPos > lastPos) {
+            // We lost an app token. Don't crash though.
+            Slog.e(TAG, "Task.addAppToken: Out of bounds attempt token=" + wtoken + " addPos="
+                    + addPos + " lastPos=" + lastPos);
+            addPos = lastPos;
+        }
         mAppTokens.add(addPos, wtoken);
+        mDeferRemoval = false;
     }
 
     boolean removeAppToken(AppWindowToken wtoken) {
-        mAppTokens.remove(wtoken);
+        boolean removed = mAppTokens.remove(wtoken);
         if (mAppTokens.size() == 0) {
             EventLog.writeEvent(com.android.server.EventLogTags.WM_TASK_REMOVED, taskId,
                     "removeAppToken: last token");
-            mStack.removeTask(this);
-            return true;
         }
-        return false;
+        return removed;
     }
 
     @Override
diff --git a/services/java/com/android/server/wm/TaskGroup.java b/services/core/java/com/android/server/wm/TaskGroup.java
similarity index 100%
rename from services/java/com/android/server/wm/TaskGroup.java
rename to services/core/java/com/android/server/wm/TaskGroup.java
diff --git a/services/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
similarity index 70%
rename from services/java/com/android/server/wm/TaskStack.java
rename to services/core/java/com/android/server/wm/TaskStack.java
index cb29df4..81db8b3 100644
--- a/services/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -26,8 +26,6 @@
 import android.util.TypedValue;
 import com.android.server.EventLogTags;
 
-import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID;
-
 import java.io.PrintWriter;
 import java.util.ArrayList;
 
@@ -43,23 +41,29 @@
     private final WindowManagerService mService;
 
     /** The display this stack sits under. */
-    private final DisplayContent mDisplayContent;
+    private DisplayContent mDisplayContent;
 
     /** The Tasks that define this stack. Oldest Tasks are at the bottom. The ordering must match
      * mTaskHistory in the ActivityStack with the same mStackId */
     private final ArrayList<Task> mTasks = new ArrayList<Task>();
 
-    /** The StackBox this sits in. */
-    StackBox mStackBox;
+    /** For comparison with DisplayContent bounds. */
+    private Rect mTmpRect = new Rect();
+
+    /** Content limits relative to the DisplayContent this sits in. */
+    private Rect mBounds = new Rect();
+
+    /** Whether mBounds is fullscreen */
+    private boolean mFullscreen = true;
 
     /** Used to support {@link android.view.WindowManager.LayoutParams#FLAG_DIM_BEHIND} */
-    final DimLayer mDimLayer;
+    private DimLayer mDimLayer;
 
     /** The particular window with FLAG_DIM_BEHIND set. If null, hide mDimLayer. */
     WindowStateAnimator mDimWinAnimator;
 
     /** Support for non-zero {@link android.view.animation.Animation#getBackgroundColor()} */
-    final DimLayer mAnimationBackgroundSurface;
+    DimLayer mAnimationBackgroundSurface;
 
     /** The particular window with an Animation with non-zero background color. */
     WindowStateAnimator mAnimationBackgroundAnimator;
@@ -68,12 +72,18 @@
      * then stop any dimming. */
     boolean mDimmingTag;
 
-    TaskStack(WindowManagerService service, int stackId, DisplayContent displayContent) {
+    /** Application tokens that are exiting, but still on screen for animations. */
+    final AppTokenList mExitingAppTokens = new AppTokenList();
+
+    /** Detach this stack from its display when animation completes. */
+    boolean mDeferDetach;
+
+    TaskStack(WindowManagerService service, int stackId) {
         mService = service;
         mStackId = stackId;
-        mDisplayContent = displayContent;
-        mDimLayer = new DimLayer(service, this);
-        mAnimationBackgroundSurface = new DimLayer(service, this);
+        // TODO: remove bounds from log, they are always 0.
+        EventLog.writeEvent(EventLogTags.WM_STACK_CREATED, stackId, mBounds.left, mBounds.top,
+                mBounds.right, mBounds.bottom);
     }
 
     DisplayContent getDisplayContent() {
@@ -84,12 +94,73 @@
         return mTasks;
     }
 
-    boolean isHomeStack() {
-        return mStackId == HOME_STACK_ID;
+    void resizeWindows() {
+        final boolean underStatusBar = mBounds.top == 0;
+
+        final ArrayList<WindowState> resizingWindows = mService.mResizingWindows;
+        for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
+            final ArrayList<AppWindowToken> activities = mTasks.get(taskNdx).mAppTokens;
+            for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
+                final ArrayList<WindowState> windows = activities.get(activityNdx).allAppWindows;
+                for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
+                    final WindowState win = windows.get(winNdx);
+                    if (!resizingWindows.contains(win)) {
+                        if (WindowManagerService.DEBUG_RESIZE) Slog.d(TAG,
+                                "setBounds: Resizing " + win);
+                        resizingWindows.add(win);
+                    }
+                    win.mUnderStatusBar = underStatusBar;
+                }
+            }
+        }
     }
 
-    boolean hasSibling() {
-        return mStackBox.mParent != null;
+    boolean setBounds(Rect bounds) {
+        boolean oldFullscreen = mFullscreen;
+        if (mDisplayContent != null) {
+            mDisplayContent.getLogicalDisplayRect(mTmpRect);
+            mFullscreen = mTmpRect.equals(bounds);
+        }
+
+        if (mBounds.equals(bounds) && oldFullscreen == mFullscreen) {
+            return false;
+        }
+
+        mDimLayer.setBounds(bounds);
+        mAnimationBackgroundSurface.setBounds(bounds);
+        mBounds.set(bounds);
+
+        return true;
+    }
+
+    void getBounds(Rect out) {
+        out.set(mBounds);
+    }
+
+    void updateDisplayInfo() {
+        if (mFullscreen && mDisplayContent != null) {
+            mDisplayContent.getLogicalDisplayRect(mTmpRect);
+            setBounds(mTmpRect);
+        }
+    }
+
+    boolean isFullscreen() {
+        return mFullscreen;
+    }
+
+    boolean isAnimating() {
+        for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
+            final ArrayList<AppWindowToken> activities = mTasks.get(taskNdx).mAppTokens;
+            for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
+                final ArrayList<WindowState> windows = activities.get(activityNdx).allAppWindows;
+                for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
+                    if (windows.get(winNdx).mWinAnimator.isAnimating()) {
+                        return true;
+                    }
+                }
+            }
+        }
+        return false;
     }
 
     /**
@@ -97,9 +168,7 @@
      * @param task The task to add.
      * @param toTop Whether to add it to the top or bottom.
      */
-    boolean addTask(Task task, boolean toTop) {
-        mStackBox.makeDirty();
-
+    void addTask(Task task, boolean toTop) {
         int stackNdx;
         if (!toTop) {
             stackNdx = 0;
@@ -121,40 +190,60 @@
         mTasks.add(stackNdx, task);
 
         task.mStack = this;
-        mDisplayContent.addTask(task, toTop);
-        return mDisplayContent.moveHomeStackBox(mStackId == HOME_STACK_ID);
+        mDisplayContent.moveStack(this, true);
+        EventLog.writeEvent(EventLogTags.WM_TASK_MOVED, task.taskId, toTop ? 1 : 0, stackNdx);
     }
 
-    boolean moveTaskToTop(Task task) {
+    void moveTaskToTop(Task task) {
         if (DEBUG_TASK_MOVEMENT) Slog.d(TAG, "moveTaskToTop: task=" + task + " Callers="
                 + Debug.getCallers(6));
         mTasks.remove(task);
-        return addTask(task, true);
+        addTask(task, true);
     }
 
-    boolean moveTaskToBottom(Task task) {
+    void moveTaskToBottom(Task task) {
         if (DEBUG_TASK_MOVEMENT) Slog.d(TAG, "moveTaskToBottom: task=" + task);
         mTasks.remove(task);
-        return addTask(task, false);
+        addTask(task, false);
     }
 
     /**
-     * Delete a Task from this stack. If it is the last Task in the stack, remove this stack from
-     * its parent StackBox and merge the parent.
+     * Delete a Task from this stack. If it is the last Task in the stack, move this stack to the
+     * back.
      * @param task The Task to delete.
      */
     void removeTask(Task task) {
         if (DEBUG_TASK_MOVEMENT) Slog.d(TAG, "removeTask: task=" + task);
-        mStackBox.makeDirty();
         mTasks.remove(task);
-        mDisplayContent.removeTask(task);
+        if (mDisplayContent != null) {
+            if (mTasks.isEmpty()) {
+                mDisplayContent.moveStack(this, false);
+            }
+            mDisplayContent.layoutNeeded = true;
+        }
     }
 
-    int remove() {
-        mAnimationBackgroundSurface.destroySurface();
-        mDimLayer.destroySurface();
+    void attachDisplayContent(DisplayContent displayContent) {
+        if (mDisplayContent != null) {
+            throw new IllegalStateException("attachDisplayContent: Already attached");
+        }
+
+        mDisplayContent = displayContent;
+        mDimLayer = new DimLayer(mService, this, displayContent);
+        mAnimationBackgroundSurface = new DimLayer(mService, this, displayContent);
+        updateDisplayInfo();
+    }
+
+    void detachDisplay() {
         EventLog.writeEvent(EventLogTags.WM_STACK_REMOVED, mStackId);
-        return mStackBox.remove();
+        for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
+            mService.tmpRemoveTaskWindowsLocked(mTasks.get(taskNdx));
+        }
+        mAnimationBackgroundSurface.destroySurface();
+        mAnimationBackgroundSurface = null;
+        mDimLayer.destroySurface();
+        mDimLayer = null;
+        mDisplayContent = null;
     }
 
     void resetAnimationBackgroundAnimator() {
@@ -259,28 +348,6 @@
         }
     }
 
-    void setBounds(Rect bounds, boolean underStatusBar) {
-        mDimLayer.setBounds(bounds);
-        mAnimationBackgroundSurface.setBounds(bounds);
-
-        final ArrayList<WindowState> resizingWindows = mService.mResizingWindows;
-        for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
-            final ArrayList<AppWindowToken> activities = mTasks.get(taskNdx).mAppTokens;
-            for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
-                final ArrayList<WindowState> windows = activities.get(activityNdx).allAppWindows;
-                for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
-                    final WindowState win = windows.get(winNdx);
-                    if (!resizingWindows.contains(win)) {
-                        if (WindowManagerService.DEBUG_RESIZE) Slog.d(TAG,
-                                "setBounds: Resizing " + win);
-                        resizingWindows.add(win);
-                    }
-                    win.mUnderStatusBar = underStatusBar;
-                }
-            }
-        }
-    }
-
     void switchUser(int userId) {
         int top = mTasks.size();
         for (int taskNdx = 0; taskNdx < top; ++taskNdx) {
@@ -293,8 +360,14 @@
         }
     }
 
+    void close() {
+        mDimLayer.mDimSurface.destroy();
+        mAnimationBackgroundSurface.mDimSurface.destroy();
+    }
+
     public void dump(String prefix, PrintWriter pw) {
         pw.print(prefix); pw.print("mStackId="); pw.println(mStackId);
+        pw.print(prefix); pw.print("mDeferDetach="); pw.println(mDeferDetach);
         for (int taskNdx = 0; taskNdx < mTasks.size(); ++taskNdx) {
             pw.print(prefix); pw.println(mTasks.get(taskNdx));
         }
@@ -307,6 +380,17 @@
             mDimLayer.printTo(prefix, pw);
             pw.print(prefix); pw.print("mDimWinAnimator="); pw.println(mDimWinAnimator);
         }
+        if (!mExitingAppTokens.isEmpty()) {
+            pw.println();
+            pw.println("  Exiting application tokens:");
+            for (int i=mExitingAppTokens.size()-1; i>=0; i--) {
+                WindowToken token = mExitingAppTokens.get(i);
+                pw.print("  Exiting App #"); pw.print(i);
+                pw.print(' '); pw.print(token);
+                pw.println(':');
+                token.dump(pw, "    ");
+            }
+        }
     }
 
     @Override
diff --git a/services/java/com/android/server/wm/ViewServer.java b/services/core/java/com/android/server/wm/ViewServer.java
similarity index 100%
rename from services/java/com/android/server/wm/ViewServer.java
rename to services/core/java/com/android/server/wm/ViewServer.java
diff --git a/services/java/com/android/server/wm/Watermark.java b/services/core/java/com/android/server/wm/Watermark.java
similarity index 100%
rename from services/java/com/android/server/wm/Watermark.java
rename to services/core/java/com/android/server/wm/Watermark.java
diff --git a/services/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
similarity index 90%
rename from services/java/com/android/server/wm/WindowAnimator.java
rename to services/core/java/com/android/server/wm/WindowAnimator.java
index 91f15f3..0c68258 100644
--- a/services/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -1,4 +1,18 @@
-// Copyright 2012 Google Inc. All Rights Reserved.
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 
 package com.android.server.wm;
 
@@ -64,7 +78,7 @@
     Object mLastWindowFreezeSource;
 
     SparseArray<DisplayContentsAnimator> mDisplayContentsAnimators =
-            new SparseArray<WindowAnimator.DisplayContentsAnimator>(2);
+            new SparseArray<DisplayContentsAnimator>(2);
 
     boolean mInitialized = false;
 
@@ -151,14 +165,33 @@
     }
 
     private void updateAppWindowsLocked(int displayId) {
-        final DisplayContent displayContent = mService.getDisplayContentLocked(displayId);
-        final ArrayList<Task> tasks = displayContent.getTasks();
-        final int numTasks = tasks.size();
-        for (int taskNdx = 0; taskNdx < numTasks; ++taskNdx) {
-            final AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
-            final int numTokens = tokens.size();
-            for (int tokenNdx = 0; tokenNdx < numTokens; ++tokenNdx) {
-                final AppWindowAnimator appAnimator = tokens.get(tokenNdx).mAppAnimator;
+        ArrayList<TaskStack> stacks = mService.getDisplayContentLocked(displayId).getStacks();
+        for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+            final TaskStack stack = stacks.get(stackNdx);
+            final ArrayList<Task> tasks = stack.getTasks();
+            for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
+                final AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
+                for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
+                    final AppWindowAnimator appAnimator = tokens.get(tokenNdx).mAppAnimator;
+                    final boolean wasAnimating = appAnimator.animation != null
+                            && appAnimator.animation != AppWindowAnimator.sDummyAnimation;
+                    if (appAnimator.stepAnimationLocked(mCurrentTime)) {
+                        mAnimating = true;
+                    } else if (wasAnimating) {
+                        // stopped animating, do one more pass through the layout
+                        setAppLayoutChanges(appAnimator,
+                                WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER,
+                                "appToken " + appAnimator.mAppToken + " done");
+                        if (WindowManagerService.DEBUG_ANIM) Slog.v(TAG,
+                                "updateWindowsApps...: done animating " + appAnimator.mAppToken);
+                    }
+                }
+            }
+
+            final AppTokenList exitingAppTokens = stack.mExitingAppTokens;
+            final int NEAT = exitingAppTokens.size();
+            for (int i = 0; i < NEAT; i++) {
+                final AppWindowAnimator appAnimator = exitingAppTokens.get(i).mAppAnimator;
                 final boolean wasAnimating = appAnimator.animation != null
                         && appAnimator.animation != AppWindowAnimator.sDummyAnimation;
                 if (appAnimator.stepAnimationLocked(mCurrentTime)) {
@@ -166,29 +199,12 @@
                 } else if (wasAnimating) {
                     // stopped animating, do one more pass through the layout
                     setAppLayoutChanges(appAnimator, WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER,
-                            "appToken " + appAnimator.mAppToken + " done");
+                        "exiting appToken " + appAnimator.mAppToken + " done");
                     if (WindowManagerService.DEBUG_ANIM) Slog.v(TAG,
-                            "updateWindowsApps...: done animating " + appAnimator.mAppToken);
+                            "updateWindowsApps...: done animating exiting " + appAnimator.mAppToken);
                 }
             }
         }
-
-        final AppTokenList exitingAppTokens = displayContent.mExitingAppTokens;
-        final int NEAT = exitingAppTokens.size();
-        for (int i = 0; i < NEAT; i++) {
-            final AppWindowAnimator appAnimator = exitingAppTokens.get(i).mAppAnimator;
-            final boolean wasAnimating = appAnimator.animation != null
-                    && appAnimator.animation != AppWindowAnimator.sDummyAnimation;
-            if (appAnimator.stepAnimationLocked(mCurrentTime)) {
-                mAnimating = true;
-            } else if (wasAnimating) {
-                // stopped animating, do one more pass through the layout
-                setAppLayoutChanges(appAnimator, WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER,
-                    "exiting appToken " + appAnimator.mAppToken + " done");
-                if (WindowManagerService.DEBUG_ANIM) Slog.v(TAG,
-                        "updateWindowsApps...: done animating exiting " + appAnimator.mAppToken);
-            }
-        }
     }
 
     private void updateWindowsLocked(final int displayId) {
@@ -449,11 +465,6 @@
         }
     }
 
-    private void performAnimationsLocked(final int displayId) {
-        updateWindowsLocked(displayId);
-        updateWallpaperLocked(displayId);
-    }
-
 
     /** Locked on mService.mWindowMap. */
     private void animateLocked() {
@@ -494,7 +505,8 @@
 
                 // Update animations of all applications, including those
                 // associated with exiting/removed apps
-                performAnimationsLocked(displayId);
+                updateWindowsLocked(displayId);
+                updateWallpaperLocked(displayId);
 
                 final WindowList windows = mService.getWindowListLocked(displayId);
                 final int N = windows.size();
@@ -642,11 +654,16 @@
     }
 
     int getPendingLayoutChanges(final int displayId) {
+        if (displayId < 0) {
+            return 0;
+        }
         return mService.getDisplayContentLocked(displayId).pendingLayoutChanges;
     }
 
     void setPendingLayoutChanges(final int displayId, final int changes) {
-        mService.getDisplayContentLocked(displayId).pendingLayoutChanges |= changes;
+        if (displayId >= 0) {
+            mService.getDisplayContentLocked(displayId).pendingLayoutChanges |= changes;
+        }
     }
 
     void setAppLayoutChanges(final AppWindowAnimator appAnimator, final int changes, String s) {
@@ -655,7 +672,7 @@
         WindowList windows = appAnimator.mAppToken.allAppWindows;
         for (int i = windows.size() - 1; i >= 0; i--) {
             final int displayId = windows.get(i).getDisplayId();
-            if (displays.indexOfKey(displayId) < 0) {
+            if (displayId >= 0 && displays.indexOfKey(displayId) < 0) {
                 setPendingLayoutChanges(displayId, changes);
                 if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
                     mService.debugLayoutRepeats(s, getPendingLayoutChanges(displayId));
@@ -676,10 +693,15 @@
     }
 
     void setScreenRotationAnimationLocked(int displayId, ScreenRotationAnimation animation) {
-        getDisplayContentsAnimatorLocked(displayId).mScreenRotationAnimation = animation;
+        if (displayId >= 0) {
+            getDisplayContentsAnimatorLocked(displayId).mScreenRotationAnimation = animation;
+        }
     }
 
     ScreenRotationAnimation getScreenRotationAnimationLocked(int displayId) {
+        if (displayId < 0) {
+            return null;
+        }
         return getDisplayContentsAnimatorLocked(displayId).mScreenRotationAnimation;
     }
 
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
similarity index 95%
rename from services/java/com/android/server/wm/WindowManagerService.java
rename to services/core/java/com/android/server/wm/WindowManagerService.java
index 096921d..6cdbdeb 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -18,11 +18,10 @@
 
 import static android.view.WindowManager.LayoutParams.*;
 
-import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID;
-
 import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
 
 import android.app.AppOpsManager;
+import android.util.ArraySet;
 import android.util.TimeUtils;
 import android.view.IWindowId;
 
@@ -35,17 +34,16 @@
 import com.android.internal.view.IInputMethodManager;
 import com.android.internal.view.WindowManagerPolicyThread;
 import com.android.server.AttributeCache;
+import com.android.server.DisplayThread;
 import com.android.server.EventLogTags;
+import com.android.server.LocalServices;
 import com.android.server.UiThread;
 import com.android.server.Watchdog;
 import com.android.server.am.BatteryStatsService;
-import com.android.server.display.DisplayManagerService;
 import com.android.server.input.InputManagerService;
-import com.android.server.power.PowerManagerService;
 import com.android.server.power.ShutdownThread;
 
 import android.Manifest;
-import android.app.ActivityManager.StackBoxInfo;
 import android.app.ActivityManagerNative;
 import android.app.IActivityManager;
 import android.app.StatusBarManager;
@@ -69,6 +67,7 @@
 import android.graphics.RectF;
 import android.graphics.Region;
 import android.hardware.display.DisplayManager;
+import android.hardware.display.DisplayManagerInternal;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Debug;
@@ -80,6 +79,7 @@
 import android.os.Parcel;
 import android.os.ParcelFileDescriptor;
 import android.os.PowerManager;
+import android.os.PowerManagerInternal;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -117,6 +117,7 @@
 import android.view.KeyEvent;
 import android.view.MagnificationSpec;
 import android.view.MotionEvent;
+import android.view.WindowManagerInternal;
 import android.view.Surface.OutOfResourcesException;
 import android.view.Surface;
 import android.view.SurfaceControl;
@@ -155,8 +156,7 @@
 
 /** {@hide} */
 public class WindowManagerService extends IWindowManager.Stub
-        implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs,
-                DisplayManagerService.WindowManagerFuncs, DisplayManager.DisplayListener {
+        implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {
     static final String TAG = "WindowManager";
     static final boolean DEBUG = false;
     static final boolean DEBUG_ADD_REMOVE = false;
@@ -188,6 +188,7 @@
     static final boolean DEBUG_WINDOW_TRACE = false;
     static final boolean DEBUG_TASK_MOVEMENT = false;
     static final boolean DEBUG_STACK = false;
+    static final boolean DEBUG_DISPLAY = false;
     static final boolean SHOW_SURFACE_ALLOC = false;
     static final boolean SHOW_TRANSACTIONS = false;
     static final boolean SHOW_LIGHT_TRANSACTIONS = false || SHOW_TRANSACTIONS;
@@ -272,10 +273,10 @@
     // Default input dispatching timeout in nanoseconds.
     static final long DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS = 5000 * 1000000L;
 
-    /** Minimum value for createStack and resizeStack weight value */
+    /** Minimum value for attachStack and resizeStack weight value */
     public static final float STACK_WEIGHT_MIN = 0.2f;
 
-    /** Maximum value for createStack and resizeStack weight value */
+    /** Maximum value for attachStack and resizeStack weight value */
     public static final float STACK_WEIGHT_MAX = 0.8f;
 
     static final int UPDATE_FOCUS_NORMAL = 0;
@@ -293,8 +294,6 @@
 
     final private KeyguardDisableHandler mKeyguardDisableHandler;
 
-    private final boolean mHeadless;
-
     final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -369,6 +368,11 @@
     final ArrayList<WindowState> mPendingRemove = new ArrayList<WindowState>();
 
     /**
+     * Stacks whose animations have ended and whose tasks, apps, selves may now be removed.
+     */
+    final ArraySet<TaskStack> mPendingStacksRemove = new ArraySet<TaskStack>();
+
+    /**
      * Used when processing mPendingRemove to avoid working on the original array.
      */
     WindowState[] mPendingRemoveTmp = new WindowState[20];
@@ -415,6 +419,7 @@
     final SurfaceSession mFxSession;
     Watermark mWatermark;
     StrictModeFlash mStrictModeFlash;
+    CircularDisplayMask mCircularDisplayMask;
     FocusedStackFrame mFocusedStackFrame;
 
     int mFocusedStackLayer;
@@ -541,14 +546,15 @@
 
     AppWindowToken mFocusedApp = null;
 
-    PowerManagerService mPowerManager;
+    PowerManager mPowerManager;
+    PowerManagerInternal mPowerManagerInternal;
 
     float mWindowAnimationScale = 1.0f;
     float mTransitionAnimationScale = 1.0f;
     float mAnimatorDurationScale = 1.0f;
 
     final InputManagerService mInputManager;
-    final DisplayManagerService mDisplayManagerService;
+    final DisplayManagerInternal mDisplayManagerInternal;
     final DisplayManager mDisplayManager;
 
     // Who is holding the screen on.
@@ -607,6 +613,9 @@
     final WindowAnimator mAnimator;
 
     SparseArray<Task> mTaskIdToTask = new SparseArray<Task>();
+
+    /** All of the TaskStacks in the window manager, unordered. For an ordered list call
+     * DisplayContent.getStacks(). */
     SparseArray<TaskStack> mStackIdToStack = new SparseArray<TaskStack>();
 
     private final PointerEventDispatcher mPointerEventDispatcher;
@@ -701,23 +710,22 @@
     final boolean mOnlyCore;
 
     public static WindowManagerService main(final Context context,
-            final PowerManagerService pm, final DisplayManagerService dm,
-            final InputManagerService im, final Handler wmHandler,
+            final InputManagerService im,
             final boolean haveInputMethods, final boolean showBootMsgs,
             final boolean onlyCore) {
         final WindowManagerService[] holder = new WindowManagerService[1];
-        wmHandler.runWithScissors(new Runnable() {
+        DisplayThread.getHandler().runWithScissors(new Runnable() {
             @Override
             public void run() {
-                holder[0] = new WindowManagerService(context, pm, dm, im,
+                holder[0] = new WindowManagerService(context, im,
                         haveInputMethods, showBootMsgs, onlyCore);
             }
         }, 0);
         return holder[0];
     }
 
-    private void initPolicy(Handler uiHandler) {
-        uiHandler.runWithScissors(new Runnable() {
+    private void initPolicy() {
+        UiThread.getHandler().runWithScissors(new Runnable() {
             @Override
             public void run() {
                 WindowManagerPolicyThread.set(Thread.currentThread(), Looper.myLooper());
@@ -730,8 +738,7 @@
         }, 0);
     }
 
-    private WindowManagerService(Context context, PowerManagerService pm,
-            DisplayManagerService displayManager, InputManagerService inputManager,
+    private WindowManagerService(Context context, InputManagerService inputManager,
             boolean haveInputMethods, boolean showBootMsgs, boolean onlyCore) {
         mContext = context;
         mHaveInputMethods = haveInputMethods;
@@ -740,8 +747,7 @@
         mLimitedAlphaCompositing = context.getResources().getBoolean(
                 com.android.internal.R.bool.config_sf_limitedAlpha);
         mInputManager = inputManager; // Must be before createDisplayContentLocked.
-        mDisplayManagerService = displayManager;
-        mHeadless = displayManager.isHeadless();
+        mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
         mDisplaySettings = new DisplaySettings(context);
         mDisplaySettings.readSettingsLocked();
 
@@ -749,7 +755,6 @@
 
         mFxSession = new SurfaceSession();
         mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
-        mDisplayManager.registerDisplayListener(this, null);
         Display[] displays = mDisplayManager.getDisplays();
         for (Display display : displays) {
             createDisplayContentLocked(display);
@@ -757,10 +762,11 @@
 
         mKeyguardDisableHandler = new KeyguardDisableHandler(mContext, mPolicy);
 
-        mPowerManager = pm;
-        mPowerManager.setPolicy(mPolicy);
-        PowerManager pmc = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
-        mScreenFrozenLock = pmc.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "SCREEN_FROZEN");
+        mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
+        mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
+        mPowerManagerInternal.setPolicy(mPolicy); // TODO: register as local service instead
+        mScreenFrozenLock = mPowerManager.newWakeLock(
+                PowerManager.PARTIAL_WAKE_LOCK, "SCREEN_FROZEN");
         mScreenFrozenLock.setReferenceCounted(false);
 
         mAppTransition = new AppTransition(context, mH);
@@ -790,13 +796,13 @@
         filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
         mContext.registerReceiver(mBroadcastReceiver, filter);
 
-        mHoldingScreenWakeLock = pmc.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK
-                | PowerManager.ON_AFTER_RELEASE, TAG);
+        mHoldingScreenWakeLock = mPowerManager.newWakeLock(
+                PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE, TAG);
         mHoldingScreenWakeLock.setReferenceCounted(false);
 
         mAnimator = new WindowAnimator(this);
 
-        initPolicy(UiThread.getHandler());
+        initPolicy();
 
         // Add ourself to the Watchdog monitors.
         Watchdog.getInstance().addMonitor(this);
@@ -809,6 +815,9 @@
         } finally {
             SurfaceControl.closeTransaction();
         }
+
+        LocalServices.addService(WindowManagerInternal.class, new LocalService());
+        showCircularDisplayMaskIfNeeded();
     }
 
     public InputMonitor getInputMonitor() {
@@ -878,7 +887,7 @@
         final int count = token.windows.size();
         for (int i = 0; i < count; i++) {
             final WindowState win = token.windows.get(i);
-            if (win.mDisplayContent == displayContent) {
+            if (win.getDisplayContent() == displayContent) {
                 windowList.add(win);
             }
         }
@@ -909,7 +918,11 @@
     private int addAppWindowToListLocked(final WindowState win) {
         final IWindow client = win.mClient;
         final WindowToken token = win.mToken;
-        final DisplayContent displayContent = win.mDisplayContent;
+        final DisplayContent displayContent = win.getDisplayContent();
+        if (displayContent == null) {
+            // It doesn't matter this display is going away.
+            return 0;
+        }
 
         final WindowList windows = win.getWindowList();
         final int N = windows.size();
@@ -1086,7 +1099,10 @@
 
     private void addAttachedWindowToListLocked(final WindowState win, boolean addToToken) {
         final WindowToken token = win.mToken;
-        final DisplayContent displayContent = win.mDisplayContent;
+        final DisplayContent displayContent = win.getDisplayContent();
+        if (displayContent == null) {
+            return;
+        }
         final WindowState attached = win.mAttachedWindow;
 
         WindowList tokenWindowList = getTokenWindowsOnDisplay(token, displayContent);
@@ -2020,7 +2036,10 @@
     }
 
     void updateWallpaperOffsetLocked(WindowState changingTarget, boolean sync) {
-        final DisplayContent displayContent = changingTarget.mDisplayContent;
+        final DisplayContent displayContent = changingTarget.getDisplayContent();
+        if (displayContent == null) {
+            return;
+        }
         final DisplayInfo displayInfo = displayContent.getDisplayInfo();
         final int dw = displayInfo.logicalWidth;
         final int dh = displayInfo.logicalHeight;
@@ -2080,7 +2099,10 @@
 
     void updateWallpaperVisibilityLocked() {
         final boolean visible = isWallpaperVisible(mWallpaperTarget);
-        final DisplayContent displayContent = mWallpaperTarget.mDisplayContent;
+        final DisplayContent displayContent = mWallpaperTarget.getDisplayContent();
+        if (displayContent == null) {
+            return;
+        }
         final DisplayInfo displayInfo = displayContent.getDisplayInfo();
         final int dw = displayInfo.logicalWidth;
         final int dh = displayInfo.logicalHeight;
@@ -2238,6 +2260,11 @@
                 return WindowManagerGlobal.ADD_APP_EXITING;
             }
 
+            if (win.getDisplayContent() == null) {
+                Slog.w(TAG, "Adding window to Display that has been removed.");
+                return WindowManagerGlobal.ADD_INVALID_DISPLAY;
+            }
+
             mPolicy.adjustWindowParamsLw(win.mAttrs);
             win.setShowToOwnerOnlyLocked(mPolicy.checkShowToOwnerOnly(attrs));
 
@@ -2380,11 +2407,6 @@
     }
 
     public void removeWindowLocked(Session session, WindowState win) {
-        removeWindowLocked(session, win, false);
-    }
-
-    private void removeWindowLocked(Session session, WindowState win,
-            boolean forceRemove) {
         if (win.mAttrs.type == TYPE_APPLICATION_STARTING) {
             if (DEBUG_STARTING_WINDOW) Slog.d(TAG, "Starting window removed " + win);
             removeStartingWindowTimeout(win.mAppToken);
@@ -2435,12 +2457,15 @@
                     mDisplayMagnifier.onWindowTransitionLocked(win, transit);
                 }
             }
-            if (!forceRemove && (win.mExiting || win.mWinAnimator.isAnimating())) {
+            if (win.mExiting || win.mWinAnimator.isAnimating()) {
                 // The exit animation is running... wait for it!
                 //Slog.i(TAG, "*** Running exit animation...");
                 win.mExiting = true;
                 win.mRemoveOnExit = true;
-                win.mDisplayContent.layoutNeeded = true;
+                final DisplayContent displayContent = win.getDisplayContent();
+                if (displayContent != null) {
+                    displayContent.layoutNeeded = true;
+                }
                 updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
                         false /*updateInputWindows*/);
                 performLayoutAndPlaceSurfacesLocked();
@@ -2497,8 +2522,6 @@
             mAppOps.finishOp(win.mAppOp, win.getOwningUid(), win.getOwningPackage());
         }
 
-        final WindowList windows = win.getWindowList();
-        windows.remove(win);
         mPendingRemove.remove(win);
         mResizingWindows.remove(win);
         mWindowsChanged = true;
@@ -2554,12 +2577,19 @@
                     WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
         }
 
-        if (!mInLayout) {
-            assignLayersLocked(windows);
-            win.mDisplayContent.layoutNeeded = true;
-            performLayoutAndPlaceSurfacesLocked();
-            if (win.mAppToken != null) {
-                win.mAppToken.updateReportedVisibilityLocked();
+        final WindowList windows = win.getWindowList();
+        if (windows != null) {
+            windows.remove(win);
+            if (!mInLayout) {
+                assignLayersLocked(windows);
+                final DisplayContent displayContent = win.getDisplayContent();
+                if (displayContent != null) {
+                    displayContent.layoutNeeded = true;
+                }
+                performLayoutAndPlaceSurfacesLocked();
+                if (win.mAppToken != null) {
+                    win.mAppToken.updateReportedVisibilityLocked();
+                }
             }
         }
 
@@ -2634,7 +2664,10 @@
                         w.mGivenVisibleInsets.scale(w.mGlobalScale);
                         w.mGivenTouchableRegion.scale(w.mGlobalScale);
                     }
-                    w.mDisplayContent.layoutNeeded = true;
+                    final DisplayContent displayContent = w.getDisplayContent();
+                    if (displayContent != null) {
+                        displayContent.layoutNeeded = true;
+                    }
                     performLayoutAndPlaceSurfacesLocked();
                 }
             }
@@ -2720,7 +2753,12 @@
         mTmpFloats[Matrix.MSKEW_X] = dsdy;
         mTmpFloats[Matrix.MSCALE_Y] = dtdy;
         matrix.setValues(mTmpFloats);
-        final DisplayInfo displayInfo = window.mDisplayContent.getDisplayInfo();
+        final DisplayContent displayContent = window.getDisplayContent();
+        if (displayContent == null) {
+            return;
+        }
+
+        final DisplayInfo displayInfo = displayContent.getDisplayInfo();
         final RectF dispRect = new RectF(0, 0,
                 displayInfo.logicalWidth, displayInfo.logicalHeight);
         matrix.mapRect(dispRect);
@@ -2729,7 +2767,7 @@
         window.mGivenTouchableRegion.op((int)dispRect.left, (int)dispRect.top,
                 (int)dispRect.right, (int)dispRect.bottom, Region.Op.DIFFERENCE);
         window.mTouchableInsets = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION;
-        window.mDisplayContent.layoutNeeded = true;
+        displayContent.layoutNeeded = true;
         performLayoutAndPlaceSurfacesLocked();
     }
 
@@ -3010,7 +3048,10 @@
                         WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
             }
 
-            win.mDisplayContent.layoutNeeded = true;
+            final DisplayContent displayContent = win.getDisplayContent();
+            if (displayContent != null) {
+                displayContent.layoutNeeded = true;
+            }
             win.mGivenInsetsPending = (flags&WindowManagerGlobal.RELAYOUT_INSETS_PENDING) != 0;
             configChanged = updateOrientationFromAppTokensLocked(false);
             performLayoutAndPlaceSurfacesLocked();
@@ -3104,7 +3145,10 @@
                         getDefaultDisplayContentLocked().pendingLayoutChanges |=
                                 WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
                     }
-                    win.mDisplayContent.layoutNeeded = true;
+                    final DisplayContent displayContent = win.getDisplayContent();
+                    if (displayContent != null) {
+                        displayContent.layoutNeeded = true;
+                    }
                     requestTraversalLocked();
                 }
             }
@@ -3362,7 +3406,7 @@
 
                     for (int i=0; i<N; i++) {
                         WindowState win = wtoken.windows.get(i);
-                        displayContent = win.mDisplayContent;
+                        displayContent = win.getDisplayContent();
 
                         if (win.mWinAnimator.isAnimating()) {
                             delayed = true;
@@ -3377,7 +3421,9 @@
                                         WindowManagerPolicy.TRANSIT_EXIT);
                             }
                             changed = true;
-                            displayContent.layoutNeeded = true;
+                            if (displayContent != null) {
+                                displayContent.layoutNeeded = true;
+                            }
                         }
                     }
 
@@ -3390,7 +3436,9 @@
                     }
 
                     if (delayed) {
-                        displayContent.mExitingTokens.add(wtoken);
+                        if (displayContent != null) {
+                            displayContent.mExitingTokens.add(wtoken);
+                        }
                     } else if (wtoken.windowType == TYPE_WALLPAPER) {
                         mWallpaperTokens.remove(wtoken);
                     }
@@ -3405,6 +3453,8 @@
     }
 
     private Task createTask(int taskId, int stackId, int userId, AppWindowToken atoken) {
+        if (DEBUG_STACK) Slog.i(TAG, "createTask: taskId=" + taskId + " stackId=" + stackId
+                + " atoken=" + atoken);
         final TaskStack stack = mStackIdToStack.get(stackId);
         if (stack == null) {
             throw new IllegalArgumentException("addAppToken: invalid stackId=" + stackId);
@@ -3458,7 +3508,7 @@
 
             Task task = mTaskIdToTask.get(taskId);
             if (task == null) {
-                task = createTask(taskId, stackId, userId, atoken);
+                createTask(taskId, stackId, userId, atoken);
             } else {
                 task.addAppToken(addPos, atoken);
             }
@@ -3486,8 +3536,8 @@
                 Slog.w(TAG, "Attempted to set group id of non-existing app token: " + token);
                 return;
             }
-            Task oldTask = mTaskIdToTask.get(atoken.groupId);
-            oldTask.removeAppToken(atoken);
+            final Task oldTask = mTaskIdToTask.get(atoken.groupId);
+            removeAppFromTaskLocked(atoken);
 
             atoken.groupId = groupId;
             Task newTask = mTaskIdToTask.get(groupId);
@@ -3639,7 +3689,7 @@
             if (freezeThisOneIfNeeded != null) {
                 AppWindowToken atoken = findAppWindowToken(freezeThisOneIfNeeded);
                 if (atoken != null) {
-                    startAppFreezingScreenLocked(atoken, ActivityInfo.CONFIG_ORIENTATION);
+                    startAppFreezingScreenLocked(atoken);
                 }
             }
             config = computeNewConfigurationLocked();
@@ -3781,7 +3831,10 @@
         if (mFocusedApp != null) {
             Task task = mTaskIdToTask.get(mFocusedApp.groupId);
             stack = task.mStack;
-            task.getDisplayContent().setTouchExcludeRegion(stack);
+            final DisplayContent displayContent = task.getDisplayContent();
+            if (displayContent != null) {
+                displayContent.setTouchExcludeRegion(stack);
+            }
         } else {
             stack = null;
         }
@@ -3791,10 +3844,8 @@
             if (stack == null) {
                 mFocusedStackFrame.setVisibility(false);
             } else {
-                final StackBox box = stack.mStackBox;
-                final Rect bounds = box.mBounds;
-                final boolean multipleStacks = box.mParent != null;
-                mFocusedStackFrame.setBounds(bounds);
+                mFocusedStackFrame.setBounds(stack);
+                final boolean multipleStacks = !stack.isFullscreen();
                 mFocusedStackFrame.setVisibility(multipleStacks);
             }
         } finally {
@@ -3811,27 +3862,23 @@
         }
 
         synchronized(mWindowMap) {
-            boolean changed = false;
+            final AppWindowToken newFocus;
             if (token == null) {
                 if (DEBUG_FOCUS_LIGHT) Slog.v(TAG, "Clearing focused app, was " + mFocusedApp);
-                changed = mFocusedApp != null;
-                mFocusedApp = null;
-                if (changed) {
-                    mInputMonitor.setFocusedAppLw(null);
-                }
+                newFocus = null;
             } else {
-                AppWindowToken newFocus = findAppWindowToken(token);
+                newFocus = findAppWindowToken(token);
                 if (newFocus == null) {
                     Slog.w(TAG, "Attempted to set focus to non-existing app token: " + token);
-                    return;
                 }
-                changed = mFocusedApp != newFocus;
                 if (DEBUG_FOCUS_LIGHT) Slog.v(TAG, "Set focused app to: " + newFocus
                         + " old focus=" + mFocusedApp + " moveFocusNow=" + moveFocusNow);
+            }
+
+            final boolean changed = mFocusedApp != newFocus;
+            if (changed) {
                 mFocusedApp = newFocus;
-                if (changed) {
-                    mInputMonitor.setFocusedAppLw(newFocus);
-                }
+                mInputMonitor.setFocusedAppLw(null);
             }
 
             if (moveFocusNow && changed) {
@@ -4172,10 +4219,25 @@
         AppWindowToken atoken = findAppWindowToken(token);
         if (atoken != null) {
             atoken.appFullscreen = toOpaque;
+            // When making translucent, wait until windows below have been drawn.
+            if (toOpaque) {
+                // Making opaque so do it now.
+                setWindowOpaque(token, true);
+            }
             requestTraversal();
         }
     }
 
+    public void setWindowOpaque(IBinder token, boolean isOpaque) {
+        AppWindowToken wtoken = findAppWindowToken(token);
+        if (wtoken != null) {
+            WindowState win = wtoken.findMainWindow();
+            if (win != null) {
+                win.mWinAnimator.setOpaque(isOpaque);
+            }
+        }
+    }
+
     boolean setTokenVisibilityLocked(AppWindowToken wtoken, WindowManager.LayoutParams lp,
             boolean visible, int transit, boolean performLayout) {
         boolean delayed = false;
@@ -4232,7 +4294,10 @@
                             }
                         }
                         changed = true;
-                        win.mDisplayContent.layoutNeeded = true;
+                        final DisplayContent displayContent = win.getDisplayContent();
+                        if (displayContent != null) {
+                            displayContent.layoutNeeded = true;
+                        }
                     }
                 } else if (win.isVisibleNow()) {
                     if (!runningAppAnimation) {
@@ -4246,7 +4311,10 @@
                         }
                     }
                     changed = true;
-                    win.mDisplayContent.layoutNeeded = true;
+                    final DisplayContent displayContent = win.getDisplayContent();
+                    if (displayContent != null) {
+                        displayContent.layoutNeeded = true;
+                    }
                 }
             }
 
@@ -4394,7 +4462,10 @@
                     }
                     w.mLastFreezeDuration = 0;
                     unfrozeWindows = true;
-                    w.mDisplayContent.layoutNeeded = true;
+                    final DisplayContent displayContent = w.getDisplayContent();
+                    if (displayContent != null) {
+                        displayContent.layoutNeeded = true;
+                    }
                 }
             }
             if (force || unfrozeWindows) {
@@ -4414,8 +4485,7 @@
         }
     }
 
-    public void startAppFreezingScreenLocked(AppWindowToken wtoken,
-            int configChanges) {
+    private void startAppFreezingScreenLocked(AppWindowToken wtoken) {
         if (DEBUG_ORIENTATION) {
             RuntimeException e = null;
             if (!HIDE_STACK_CRAWLS) {
@@ -4464,7 +4534,7 @@
                 return;
             }
             final long origId = Binder.clearCallingIdentity();
-            startAppFreezingScreenLocked(wtoken, configChanges);
+            startAppFreezingScreenLocked(wtoken);
             Binder.restoreCallingIdentity(origId);
         }
     }
@@ -4489,6 +4559,15 @@
         }
     }
 
+    void removeAppFromTaskLocked(AppWindowToken wtoken) {
+        final Task task = mTaskIdToTask.get(wtoken.groupId);
+        if (task != null) {
+            if (!task.removeAppToken(wtoken)) {
+                Slog.e(TAG, "removeAppFromTaskLocked: token=" + wtoken + " not found.");
+            }
+        }
+    }
+
     @Override
     public void removeAppToken(IBinder token) {
         if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
@@ -4521,26 +4600,24 @@
                         TAG, "Removing app " + wtoken + " delayed=" + delayed
                         + " animation=" + wtoken.mAppAnimator.animation
                         + " animating=" + wtoken.mAppAnimator.animating);
-                final Task task = mTaskIdToTask.get(wtoken.groupId);
-                DisplayContent displayContent = task.getDisplayContent();
+                if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG, "removeAppToken: "
+                        + wtoken + " delayed=" + delayed + " Callers=" + Debug.getCallers(4));
+                final TaskStack stack = mTaskIdToTask.get(wtoken.groupId).mStack;
                 if (delayed) {
                     // set the token aside because it has an active animation to be finished
                     if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
                             "removeAppToken make exiting: " + wtoken);
-                    displayContent.mExitingAppTokens.add(wtoken);
+                    stack.mExitingAppTokens.add(wtoken);
+                    wtoken.mDeferRemoval = true;
                 } else {
                     // Make sure there is no animation running on this token,
                     // so any windows associated with it will be removed as
                     // soon as their animations are complete
                     wtoken.mAppAnimator.clearAnimation();
                     wtoken.mAppAnimator.animating = false;
+                    removeAppFromTaskLocked(wtoken);
                 }
-                if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
-                        "removeAppToken: " + wtoken);
 
-                if (task.removeAppToken(wtoken)) {
-                    mTaskIdToTask.delete(wtoken.groupId);
-                }
                 wtoken.removed = true;
                 if (wtoken.startingData != null) {
                     startingToken = wtoken;
@@ -4585,13 +4662,15 @@
             mH.sendMessage(m);
         }
     }
+
     private boolean tmpRemoveAppWindowsLocked(WindowToken token) {
-        final int NW = token.windows.size();
+        WindowList windows = token.windows;
+        final int NW = windows.size();
         if (NW > 0) {
             mWindowsChanged = true;
         }
-        for (int i=0; i<NW; i++) {
-            WindowState win = token.windows.get(i);
+        for (int i = 0; i < NW; i++) {
+            WindowState win = windows.get(i);
             if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Tmp removing app window " + win);
             win.getWindowList().remove(win);
             int j = win.mChildWindows.size();
@@ -4607,29 +4686,32 @@
     }
 
     void dumpAppTokensLocked() {
-        final int numDisplays = mDisplayContents.size();
-        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
-            final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
-            Slog.v(TAG, "  Display " + displayContent.getDisplayId());
-            final ArrayList<Task> tasks = displayContent.getTasks();
-            int i = displayContent.numTokens();
-            for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
-                AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
-                for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
-                    final AppWindowToken wtoken = tokens.get(tokenNdx);
-                    Slog.v(TAG, "  #" + --i + ": " + wtoken.token);
+        final int numStacks = mStackIdToStack.size();
+        for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
+            final TaskStack stack = mStackIdToStack.valueAt(stackNdx);
+            Slog.v(TAG, "  Stack #" + stack.mStackId + " tasks from bottom to top:");
+            final ArrayList<Task> tasks = stack.getTasks();
+            final int numTasks = tasks.size();
+            for (int taskNdx = 0; taskNdx < numTasks; ++taskNdx) {
+                final Task task = tasks.get(taskNdx);
+                Slog.v(TAG, "    Task #" + task.taskId + " activities from bottom to top:");
+                AppTokenList tokens = task.mAppTokens;
+                final int numTokens = tokens.size();
+                for (int tokenNdx = 0; tokenNdx < numTokens; ++tokenNdx) {
+                    Slog.v(TAG, "      activity #" + tokenNdx + ": " + tokens.get(tokenNdx).token);
                 }
             }
         }
     }
 
     void dumpWindowsLocked() {
-        int i = 0;
         final int numDisplays = mDisplayContents.size();
         for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
-            final WindowList windows = mDisplayContents.valueAt(displayNdx).getWindowList();
+            final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
+            Slog.v(TAG, " Display #" + displayContent.getDisplayId());
+            final WindowList windows = displayContent.getWindowList();
             for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
-                Slog.v(TAG, "  #" + i++ + ": " + windows.get(winNdx));
+                Slog.v(TAG, "  #" + winNdx + ": " + windows.get(winNdx));
             }
         }
     }
@@ -4741,23 +4823,28 @@
         final int NW = token.windows.size();
         for (int i=0; i<NW; i++) {
             final WindowState win = token.windows.get(i);
-            if (win.mDisplayContent == displayContent) {
+            final DisplayContent winDisplayContent = win.getDisplayContent();
+            if (winDisplayContent == displayContent || winDisplayContent == null) {
+                win.mDisplayContent = displayContent;
                 index = reAddWindowLocked(index, win);
             }
         }
         return index;
     }
 
+    void tmpRemoveTaskWindowsLocked(Task task) {
+        AppTokenList tokens = task.mAppTokens;
+        for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
+            tmpRemoveAppWindowsLocked(tokens.get(tokenNdx));
+        }
+    }
+
     void moveStackWindowsLocked(DisplayContent displayContent) {
         // First remove all of the windows from the list.
         final ArrayList<Task> tasks = displayContent.getTasks();
         final int numTasks = tasks.size();
         for (int taskNdx = 0; taskNdx < numTasks; ++taskNdx) {
-            AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
-            final int numTokens = tokens.size();
-            for (int tokenNdx = numTokens - 1; tokenNdx >= 0; --tokenNdx) {
-                tmpRemoveAppWindowsLocked(tokens.get(tokenNdx));
-            }
+            tmpRemoveTaskWindowsLocked(tasks.get(taskNdx));
         }
 
         // And now add them back at the correct place.
@@ -4801,10 +4888,14 @@
                 }
                 final TaskStack stack = task.mStack;
                 final DisplayContent displayContent = task.getDisplayContent();
-                final boolean isHomeStackTask = stack.isHomeStack();
-                if (isHomeStackTask != displayContent.homeOnTop()) {
-                    // First move the stack itself.
-                    displayContent.moveHomeStackBox(isHomeStackTask);
+                displayContent.moveStack(stack, true);
+                if (displayContent.isDefaultDisplay) {
+                    final TaskStack homeStack = displayContent.getHomeStack();
+                    if (homeStack != stack) {
+                        // When a non-home stack moves to the top, the home stack moves to the
+                        // bottom.
+                        displayContent.moveStack(homeStack, false);
+                    }
                 }
                 stack.moveTaskToTop(task);
             }
@@ -4833,54 +4924,74 @@
     }
 
     /**
-     * Create a new TaskStack and place it next to an existing stack.
+     * Create a new TaskStack and place it on a DisplayContent.
      * @param stackId The unique identifier of the new stack.
-     * @param relativeStackBoxId The existing stack that this stack goes before or after.
-     * @param position One of:
-     *      {@link StackBox#TASK_STACK_GOES_BEFORE}
-     *      {@link StackBox#TASK_STACK_GOES_AFTER}
-     *      {@link StackBox#TASK_STACK_GOES_ABOVE}
-     *      {@link StackBox#TASK_STACK_GOES_BELOW}
-     *      {@link StackBox#TASK_STACK_GOES_UNDER}
-     *      {@link StackBox#TASK_STACK_GOES_OVER}
-     * @param weight Relative weight for determining how big to make the new TaskStack.
+     * @param displayId The unique identifier of the DisplayContent.
      */
-    public void createStack(int stackId, int relativeStackBoxId, int position, float weight) {
-        synchronized (mWindowMap) {
-            if (position <= StackBox.TASK_STACK_GOES_BELOW &&
-                    (weight < STACK_WEIGHT_MIN || weight > STACK_WEIGHT_MAX)) {
-                throw new IllegalArgumentException(
-                        "createStack: weight must be between " + STACK_WEIGHT_MIN + " and " +
-                        STACK_WEIGHT_MAX + ", weight=" + weight);
-            }
-            final int numDisplays = mDisplayContents.size();
-            for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
-                final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
-                TaskStack stack = displayContent.createStack(stackId, relativeStackBoxId, position,
-                        weight);
-                if (stack != null) {
-                    mStackIdToStack.put(stackId, stack);
-                    performLayoutAndPlaceSurfacesLocked();
-                    return;
+    public void attachStack(int stackId, int displayId) {
+        final long origId = Binder.clearCallingIdentity();
+        try {
+            synchronized (mWindowMap) {
+                final DisplayContent displayContent = mDisplayContents.get(displayId);
+                if (displayContent != null) {
+                    TaskStack stack = mStackIdToStack.get(stackId);
+                    if (stack == null) {
+                        if (DEBUG_STACK) Slog.d(TAG, "attachStack: stackId=" + stackId);
+                        stack = new TaskStack(this, stackId);
+                        mStackIdToStack.put(stackId, stack);
+                    }
+                    stack.attachDisplayContent(displayContent);
+                    displayContent.attachStack(stack);
+                    moveStackWindowsLocked(displayContent);
+                    final WindowList windows = displayContent.getWindowList();
+                    for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
+                        windows.get(winNdx).reportResized();
+                    }
                 }
             }
-            Slog.e(TAG, "createStack: Unable to find relativeStackBoxId=" + relativeStackBoxId);
+        } finally {
+            Binder.restoreCallingIdentity(origId);
         }
     }
 
-    public int removeStack(int stackId) {
+    void detachStackLocked(DisplayContent displayContent, TaskStack stack) {
+        displayContent.detachStack(stack);
+        stack.detachDisplay();
+    }
+
+    public void detachStack(int stackId) {
         synchronized (mWindowMap) {
-            final TaskStack stack = mStackIdToStack.get(stackId);
+            TaskStack stack = mStackIdToStack.get(stackId);
             if (stack != null) {
-                mStackIdToStack.delete(stackId);
-                int nextStackId = stack.remove();
-                stack.getDisplayContent().layoutNeeded = true;
-                requestTraversalLocked();
-                return nextStackId;
+                final DisplayContent displayContent = stack.getDisplayContent();
+                if (displayContent != null) {
+                    if (stack.isAnimating()) {
+                        stack.mDeferDetach = true;
+                        return;
+                    }
+                    detachStackLocked(displayContent, stack);
+                }
             }
-            if (DEBUG_STACK) Slog.i(TAG, "removeStack: could not find stackId=" + stackId);
         }
-        return HOME_STACK_ID;
+    }
+
+    public void removeStack(int stackId) {
+        mStackIdToStack.remove(stackId);
+    }
+
+    void removeTaskLocked(Task task) {
+        final int taskId = task.taskId;
+        final TaskStack stack = task.mStack;
+        if (stack.isAnimating()) {
+            if (DEBUG_STACK) Slog.i(TAG, "removeTask: deferring removing taskId=" + taskId);
+            task.mDeferRemoval = true;
+            return;
+        }
+        if (DEBUG_STACK) Slog.i(TAG, "removeTask: removing taskId=" + taskId);
+        EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, taskId, "removeTask");
+        task.mDeferRemoval = false;
+        task.mStack.removeTask(task);
+        mTaskIdToTask.delete(task.taskId);
     }
 
     public void removeTask(int taskId) {
@@ -4890,15 +5001,14 @@
                 if (DEBUG_STACK) Slog.i(TAG, "removeTask: could not find taskId=" + taskId);
                 return;
             }
-            final TaskStack stack = task.mStack;
-            EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, taskId, "removeTask");
-            stack.removeTask(task);
-            stack.getDisplayContent().layoutNeeded = true;
+            removeTaskLocked(task);
         }
     }
 
     public void addTask(int taskId, int stackId, boolean toTop) {
         synchronized (mWindowMap) {
+            if (DEBUG_STACK) Slog.i(TAG, "addTask: adding taskId=" + taskId
+                    + " to " + (toTop ? "top" : "bottom"));
             Task task = mTaskIdToTask.get(taskId);
             if (task == null) {
                 return;
@@ -4911,40 +5021,28 @@
         }
     }
 
-    public void resizeStackBox(int stackBoxId, float weight) {
-        if (weight < STACK_WEIGHT_MIN || weight > STACK_WEIGHT_MAX) {
-            throw new IllegalArgumentException(
-                    "resizeStack: weight must be between " + STACK_WEIGHT_MIN + " and " +
-                    STACK_WEIGHT_MAX + ", weight=" + weight);
-        }
+    public void resizeStack(int stackId, Rect bounds) {
         synchronized (mWindowMap) {
-            final int numDisplays = mDisplayContents.size();
-            for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
-                if (mDisplayContents.valueAt(displayNdx).resizeStack(stackBoxId, weight)) {
-                    performLayoutAndPlaceSurfacesLocked();
-                    return;
-                }
+            final TaskStack stack = mStackIdToStack.get(stackId);
+            if (stack == null) {
+                throw new IllegalArgumentException("resizeStack: stackId " + stackId
+                        + " not found.");
             }
-        }
-        throw new IllegalArgumentException("resizeStack: stackBoxId " + stackBoxId
-                + " not found.");
-    }
-
-    public ArrayList<StackBoxInfo> getStackBoxInfos() {
-        synchronized(mWindowMap) {
-            return getDefaultDisplayContentLocked().getStackBoxInfos();
+            if (stack.setBounds(bounds)) {
+                stack.resizeWindows();
+                stack.getDisplayContent().layoutNeeded = true;
+                performLayoutAndPlaceSurfacesLocked();
+            }
         }
     }
 
-    public Rect getStackBounds(int stackId) {
-        final int numDisplays = mDisplayContents.size();
-        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
-            Rect bounds = mDisplayContents.valueAt(displayNdx).getStackBounds(stackId);
-            if (bounds != null) {
-                return bounds;
-            }
+    public void getStackBounds(int stackId, Rect bounds) {
+        final TaskStack stack = mStackIdToStack.get(stackId);
+        if (stack != null) {
+            stack.getBounds(bounds);
+            return;
         }
-        return null;
+        bounds.setEmpty();
     }
 
     // -------------------------------------------------------------
@@ -5220,7 +5318,7 @@
             final int numDisplays = mDisplayContents.size();
             for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
                 final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
-                displayContent.switchUserStacks(oldUserId, newUserId);
+                displayContent.switchUserStacks(newUserId);
                 rebuildAppWindowListLocked(displayContent);
             }
             performLayoutAndPlaceSurfacesLocked();
@@ -5272,7 +5370,7 @@
 
     public void performBootTimeout() {
         synchronized(mWindowMap) {
-            if (mDisplayEnabled || mHeadless) {
+            if (mDisplayEnabled) {
                 return;
             }
             Slog.w(TAG, "***** BOOT TIMEOUT: forcing display enabled");
@@ -5452,11 +5550,43 @@
         }
     }
 
+    public void showCircularDisplayMaskIfNeeded() {
+        // we're fullscreen and not hosted in an ActivityView
+        if (mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_windowIsRound)) {
+            mH.sendMessage(mH.obtainMessage(H.SHOW_DISPLAY_MASK));
+        }
+    }
+
+    public void showCircularMask() {
+        synchronized(mWindowMap) {
+
+            if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
+                    ">>> OPEN TRANSACTION showDisplayMask");
+            SurfaceControl.openTransaction();
+            try {
+                // TODO(multi-display): support multiple displays
+                if (mCircularDisplayMask == null) {
+                    mCircularDisplayMask = new CircularDisplayMask(
+                            getDefaultDisplayContentLocked().getDisplay(),
+                            mFxSession,
+                            mPolicy.windowTypeToLayerLw(
+                                    WindowManager.LayoutParams.TYPE_POINTER)
+                                    * TYPE_LAYER_MULTIPLIER + 10);
+                }
+                mCircularDisplayMask.setVisibility(true);
+            } finally {
+                SurfaceControl.closeTransaction();
+                if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
+                        "<<< CLOSE TRANSACTION showDisplayMask");
+            }
+        }
+    }
+
     // TODO: more accounting of which pid(s) turned it on, keep count,
     // only allow disables from pids which have count on, etc.
     @Override
     public void showStrictModeViolation(boolean on) {
-        if (mHeadless) return;
         int pid = Binder.getCallingPid();
         mH.sendMessage(mH.obtainMessage(H.SHOW_STRICT_MODE_VIOLATION, on ? 1 : 0, pid));
     }
@@ -5602,7 +5732,7 @@
                                 continue;
                             }
                             appWin = ws;
-                            stackBounds.set(ws.getStackBounds());
+                            ws.getStackBounds(stackBounds);
                         }
                     }
 
@@ -5977,7 +6107,7 @@
                 }
             }
 
-            mDisplayManagerService.performTraversalInTransactionFromWindowManager();
+            mDisplayManagerInternal.performTraversalInTransactionFromWindowManager();
         } finally {
             if (!inTransaction) {
                 SurfaceControl.closeTransaction();
@@ -6675,7 +6805,7 @@
             displayInfo.getLogicalMetrics(mRealDisplayMetrics,
                     CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
             displayInfo.getAppMetrics(mDisplayMetrics);
-            mDisplayManagerService.setDisplayInfoOverrideFromWindowManager(
+            mDisplayManagerInternal.setDisplayInfoOverrideFromWindowManager(
                     displayContent.getDisplayId(), displayInfo);
         }
         if (false) {
@@ -6909,7 +7039,6 @@
             if (mDisplayEnabled) {
                 mInputMonitor.setEventDispatchingLw(enabled);
             }
-            sendScreenStatusToClientsLocked();
         }
     }
 
@@ -7008,7 +7137,7 @@
                 synchronized(displayContent.mDisplaySizeLock) {
                     // Bootstrap the default logical display from the display manager.
                     final DisplayInfo displayInfo = displayContent.getDisplayInfo();
-                    DisplayInfo newDisplayInfo = mDisplayManagerService.getDisplayInfo(displayId);
+                    DisplayInfo newDisplayInfo = mDisplayManagerInternal.getDisplayInfo(displayId);
                     if (newDisplayInfo != null) {
                         displayInfo.copyFrom(newDisplayInfo);
                     }
@@ -7029,23 +7158,6 @@
         mPolicy.systemReady();
     }
 
-    // TODO(multidisplay): Call isScreenOn for each display.
-    private void sendScreenStatusToClientsLocked() {
-        final boolean on = mPowerManager.isScreenOn();
-        final int numDisplays = mDisplayContents.size();
-        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
-            final WindowList windows = mDisplayContents.valueAt(displayNdx).getWindowList();
-            final int numWindows = windows.size();
-            for (int winNdx = 0; winNdx < numWindows; ++winNdx) {
-                try {
-                    windows.get(winNdx).mClient.dispatchScreenState(on);
-                } catch (RemoteException e) {
-                    // Ignored
-                }
-            }
-        }
-    }
-
     // -------------------------------------------------------------
     // Async Handler
     // -------------------------------------------------------------
@@ -7086,6 +7198,8 @@
 
         public static final int REMOVE_STARTING_TIMEOUT = 33;
 
+        public static final int SHOW_DISPLAY_MASK = 34;
+
         @Override
         public void handleMessage(Message msg) {
             if (DEBUG_WINDOW_TRACE) {
@@ -7378,15 +7492,18 @@
                 case APP_FREEZE_TIMEOUT: {
                     synchronized (mWindowMap) {
                         Slog.w(TAG, "App freeze timeout expired.");
-                        DisplayContent displayContent = getDefaultDisplayContentLocked();
-                        final ArrayList<Task> tasks = displayContent.getTasks();
-                        for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
-                            AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
-                            for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
-                                AppWindowToken tok = tokens.get(tokenNdx);
-                                if (tok.mAppAnimator.freezingScreen) {
-                                    Slog.w(TAG, "Force clearing freeze: " + tok);
-                                    unsetAppFreezingScreenLocked(tok, true, true);
+                        final int numStacks = mStackIdToStack.size();
+                        for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
+                            final TaskStack stack = mStackIdToStack.valueAt(stackNdx);
+                            final ArrayList<Task> tasks = stack.getTasks();
+                            for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
+                                AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
+                                for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
+                                    AppWindowToken tok = tokens.get(tokenNdx);
+                                    if (tok.mAppAnimator.freezingScreen) {
+                                        Slog.w(TAG, "Force clearing freeze: " + tok);
+                                        unsetAppFreezingScreenLocked(tok, true, true);
+                                    }
                                 }
                             }
                         }
@@ -7484,6 +7601,11 @@
                     break;
                 }
 
+                case SHOW_DISPLAY_MASK: {
+                    showCircularMask();
+                    break;
+                }
+
                 case DO_ANIMATION_CALLBACK: {
                     try {
                         ((IRemoteCallback)msg.obj).sendResult(null);
@@ -7493,9 +7615,7 @@
                 }
 
                 case DO_DISPLAY_ADDED:
-                    synchronized (mWindowMap) {
-                        handleDisplayAddedLocked(msg.arg1);
-                    }
+                    handleDisplayAdded(msg.arg1);
                     break;
 
                 case DO_DISPLAY_REMOVED:
@@ -7954,7 +8074,6 @@
     }
 
     final void rebuildAppWindowListLocked() {
-        // TODO: Multidisplay, when ActivityStacks and tasks exist on more than one display.
         rebuildAppWindowListLocked(getDefaultDisplayContentLocked());
     }
 
@@ -7999,27 +8118,37 @@
         // in the main app list, but still have windows shown.  We put them
         // in the back because now that the animation is over we no longer
         // will care about them.
-        AppTokenList exitingAppTokens = displayContent.mExitingAppTokens;
-        int NT = exitingAppTokens.size();
-        for (int j=0; j<NT; j++) {
-            i = reAddAppWindowsLocked(displayContent, i, exitingAppTokens.get(j));
+        final ArrayList<TaskStack> stacks = displayContent.getStacks();
+        final int numStacks = stacks.size();
+        for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
+            AppTokenList exitingAppTokens = stacks.get(stackNdx).mExitingAppTokens;
+            int NT = exitingAppTokens.size();
+            for (int j = 0; j < NT; j++) {
+                i = reAddAppWindowsLocked(displayContent, i, exitingAppTokens.get(j));
+            }
         }
 
         // And add in the still active app tokens in Z order.
-        final ArrayList<Task> tasks = displayContent.getTasks();
-        final int numTasks = tasks.size();
-        for (int taskNdx = 0; taskNdx < numTasks; ++taskNdx) {
-            final AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
-            final int numTokens = tokens.size();
-            for (int tokenNdx = 0; tokenNdx < numTokens; ++tokenNdx) {
-                final AppWindowToken wtoken = tokens.get(tokenNdx);
-                i = reAddAppWindowsLocked(displayContent, i, wtoken);
+        for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
+            final ArrayList<Task> tasks = stacks.get(stackNdx).getTasks();
+            final int numTasks = tasks.size();
+            for (int taskNdx = 0; taskNdx < numTasks; ++taskNdx) {
+                final AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
+                final int numTokens = tokens.size();
+                for (int tokenNdx = 0; tokenNdx < numTokens; ++tokenNdx) {
+                    final AppWindowToken wtoken = tokens.get(tokenNdx);
+                    if (wtoken.mDeferRemoval) {
+                        continue;
+                    }
+                    i = reAddAppWindowsLocked(displayContent, i, wtoken);
+                }
             }
         }
 
         i -= lastBelow;
         if (i != numRemoved) {
-            Slog.w(TAG, "Rebuild removed " + numRemoved + " windows but added " + i,
+            Slog.w(TAG, "On display=" + displayContent.getDisplayId() + " Rebuild removed " +
+                    numRemoved + " windows but added " + i,
                     new RuntimeException("here").fillInStackTrace());
             for (i=0; i<numRemoved; i++) {
                 WindowState ws = mRebuildTmp[i];
@@ -8235,7 +8364,7 @@
         }
 
         mPolicy.getContentRectLw(mTmpContentRect);
-        displayContent.setStackBoxSize(mTmpContentRect);
+        displayContent.resize(mTmpContentRect);
 
         int seq = mLayoutSeq+1;
         if (seq < 0) seq = 0;
@@ -8379,8 +8508,7 @@
         // it frozen/off until this window draws at its new
         // orientation.
         if (!okToDisplay()) {
-            if (DEBUG_ORIENTATION) Slog.v(TAG,
-                    "Changing surface while display frozen: " + w);
+            if (DEBUG_ORIENTATION) Slog.v(TAG, "Changing surface while display frozen: " + w);
             w.mOrientationChanging = true;
             w.mLastFreezeDuration = 0;
             mInnerFields.mOrientationChangeComplete = false;
@@ -8688,15 +8816,14 @@
 
         mAppTransition.setIdle();
         // Restore window app tokens to the ActivityManager views
-        final DisplayContent displayContent = getDefaultDisplayContentLocked();
-        final ArrayList<Task> tasks = displayContent.getTasks();
-        final int numTasks = tasks.size();
-        for (int taskNdx = 0; taskNdx < numTasks; ++taskNdx) {
-            final AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
-            final int numTokens = tokens.size();
-            for (int tokenNdx = 0; tokenNdx < numTokens; ++tokenNdx) {
-                final AppWindowToken wtoken = tokens.get(tokenNdx);
-                wtoken.sendingToBottom = false;
+        ArrayList<TaskStack> stacks = getDefaultDisplayContentLocked().getStacks();
+        for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+            final ArrayList<Task> tasks = stacks.get(stackNdx).getTasks();
+            for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
+                final AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
+                for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
+                    tokens.get(tokenNdx).sendingToBottom = false;
+                }
             }
         }
         rebuildAppWindowListLocked();
@@ -8830,7 +8957,8 @@
             if (canBeSeen) {
                 // This function assumes that the contents of the default display are
                 // processed first before secondary displays.
-                if (w.mDisplayContent.isDefaultDisplay) {
+                final DisplayContent displayContent = w.getDisplayContent();
+                if (displayContent != null && displayContent.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
@@ -8839,8 +8967,9 @@
                         mInnerFields.mObscureApplicationContentOnSecondaryDisplays = true;
                     }
                     mInnerFields.mDisplayHasContent = true;
-                } else if (!mInnerFields.mObscureApplicationContentOnSecondaryDisplays
-                        || (mInnerFields.mObscured && type == TYPE_KEYGUARD_DIALOG)) {
+                } else if (displayContent != null &&
+                        (!mInnerFields.mObscureApplicationContentOnSecondaryDisplays
+                        || (mInnerFields.mObscured && type == TYPE_KEYGUARD_DIALOG))) {
                     // Allow full screen keyguard presentation dialogs to be seen.
                     mInnerFields.mDisplayHasContent = true;
                 }
@@ -8848,7 +8977,7 @@
         }
     }
 
-    private void handleFlagDimBehind(WindowState w, int innerDw, int innerDh) {
+    private void handleFlagDimBehind(WindowState w) {
         final WindowManager.LayoutParams attrs = w.mAttrs;
         if ((attrs.flags & FLAG_DIM_BEHIND) != 0
                 && w.isDisplayedLw()
@@ -8866,22 +8995,23 @@
     private void updateAllDrawnLocked(DisplayContent displayContent) {
         // See if any windows have been drawn, so they (and others
         // associated with them) can now be shown.
-        final ArrayList<Task> tasks = displayContent.getTasks();
-        final int numTasks = tasks.size();
-        for (int taskNdx = 0; taskNdx < numTasks; ++taskNdx) {
-            final AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
-            final int numTokens = tokens.size();
-            for (int tokenNdx = 0; tokenNdx < numTokens; ++tokenNdx) {
-                final AppWindowToken wtoken = tokens.get(tokenNdx);
-                if (!wtoken.allDrawn) {
-                    int numInteresting = wtoken.numInterestingWindows;
-                    if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) {
-                        if (DEBUG_VISIBILITY) Slog.v(TAG,
-                                "allDrawn: " + wtoken
-                                + " interesting=" + numInteresting
-                                + " drawn=" + wtoken.numDrawnWindows);
-                        wtoken.allDrawn = true;
-                        mH.obtainMessage(H.NOTIFY_ACTIVITY_DRAWN, wtoken.token).sendToTarget();
+        ArrayList<TaskStack> stacks = displayContent.getStacks();
+        for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+            final ArrayList<Task> tasks = stacks.get(stackNdx).getTasks();
+            for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
+                final AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
+                for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
+                    final AppWindowToken wtoken = tokens.get(tokenNdx);
+                    if (!wtoken.allDrawn) {
+                        int numInteresting = wtoken.numInterestingWindows;
+                        if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) {
+                            if (DEBUG_VISIBILITY) Slog.v(TAG,
+                                    "allDrawn: " + wtoken
+                                    + " interesting=" + numInteresting
+                                    + " drawn=" + wtoken.numDrawnWindows);
+                            wtoken.allDrawn = true;
+                            mH.obtainMessage(H.NOTIFY_ACTIVITY_DRAWN, wtoken.token).sendToTarget();
+                        }
                     }
                 }
             }
@@ -8912,10 +9042,14 @@
             for (i=displayContent.mExitingTokens.size()-1; i>=0; i--) {
                 displayContent.mExitingTokens.get(i).hasVisible = false;
             }
+        }
 
+        for (int stackNdx = mStackIdToStack.size() - 1; stackNdx >= 0; --stackNdx) {
             // Initialize state of exiting applications.
-            for (i=displayContent.mExitingAppTokens.size()-1; i>=0; i--) {
-                displayContent.mExitingAppTokens.get(i).hasVisible = false;
+            final AppTokenList exitingAppTokens =
+                    mStackIdToStack.valueAt(stackNdx).mExitingAppTokens;
+            for (int tokenNdx = exitingAppTokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
+                exitingAppTokens.get(tokenNdx).hasVisible = false;
             }
         }
 
@@ -8943,6 +9077,9 @@
             if (mStrictModeFlash != null) {
                 mStrictModeFlash.positionSurface(defaultDw, defaultDh);
             }
+            if (mCircularDisplayMask != null) {
+                mCircularDisplayMask.positionSurface(defaultDw, defaultDh, mRotation);
+            }
 
             boolean focusDisplayed = false;
 
@@ -9034,6 +9171,10 @@
                 final int N = windows.size();
                 for (i=N-1; i>=0; i--) {
                     WindowState w = windows.get(i);
+                    final TaskStack stack = w.getStack();
+                    if (stack == null) {
+                        continue;
+                    }
 
                     final boolean obscuredChanged = w.mObscured != mInnerFields.mObscured;
 
@@ -9043,8 +9184,8 @@
                         handleNotObscuredLocked(w, currentTime, innerDw, innerDh);
                     }
 
-                    if (!w.getStack().testDimmingTag()) {
-                        handleFlagDimBehind(w, innerDw, innerDh);
+                    if (!stack.testDimmingTag()) {
+                        handleFlagDimBehind(w);
                     }
 
                     if (isDefaultDisplay && obscuredChanged && (mWallpaperTarget == w)
@@ -9168,7 +9309,7 @@
                     updateResizingWindows(w);
                 }
 
-                mDisplayManagerService.setDisplayHasContent(displayId,
+                mDisplayManagerInternal.setDisplayHasContent(displayId,
                         mInnerFields.mDisplayHasContent,
                         true /* inTraversal, must call performTraversalInTrans... below */);
 
@@ -9185,7 +9326,7 @@
 
             // Give the display manager a chance to adjust properties
             // like display rotation if it needs to.
-            mDisplayManagerService.performTraversalInTransactionFromWindowManager();
+            mDisplayManagerInternal.performTraversalInTransactionFromWindowManager();
 
         } catch (RuntimeException e) {
             Log.wtf(TAG, "Unhandled exception in Window Manager", e);
@@ -9260,57 +9401,7 @@
                 // Don't remove this window until rotation has completed.
                 continue;
             }
-            final WindowStateAnimator winAnimator = win.mWinAnimator;
-            try {
-                if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG,
-                        "Reporting new frame to " + win + ": " + win.mCompatFrame);
-                int diff = 0;
-                boolean configChanged = win.isConfigChanged();
-                if ((DEBUG_RESIZE || DEBUG_ORIENTATION || DEBUG_CONFIGURATION)
-                        && configChanged) {
-                    Slog.i(TAG, "Sending new config to window " + win + ": "
-                            + winAnimator.mSurfaceW + "x" + winAnimator.mSurfaceH
-                            + " / " + mCurConfiguration + " / 0x"
-                            + Integer.toHexString(diff));
-                }
-                win.setConfiguration(mCurConfiguration);
-                if (DEBUG_ORIENTATION &&
-                        winAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING) Slog.i(
-                        TAG, "Resizing " + win + " WITH DRAW PENDING");
-                final IWindow client = win.mClient;
-                final Rect frame = win.mFrame;
-                final Rect overscanInsets = win.mLastOverscanInsets;
-                final Rect contentInsets = win.mLastContentInsets;
-                final Rect visibleInsets = win.mLastVisibleInsets;
-                final boolean reportDraw
-                        = winAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING;
-                final Configuration newConfig = configChanged ? win.mConfiguration : null;
-                if (win.mClient instanceof IWindow.Stub) {
-                    // To prevent deadlock simulate one-way call if win.mClient is a local object.
-                    mH.post(new Runnable() {
-                        @Override
-                        public void run() {
-                            try {
-                                client.resized(frame, overscanInsets, contentInsets,
-                                        visibleInsets, reportDraw, newConfig);
-                            } catch (RemoteException e) {
-                                // Not a remote call, RemoteException won't be raised.
-                            }
-                        }
-                    });
-                } else {
-                   client.resized(frame, overscanInsets, contentInsets, visibleInsets, reportDraw,
-                           newConfig);
-                }
-                win.mOverscanInsetsChanged = false;
-                win.mContentInsetsChanged = false;
-                win.mVisibleInsetsChanged = false;
-                winAnimator.mSurfaceResized = false;
-            } catch (RemoteException e) {
-                win.mOrientationChanging = false;
-                win.mLastFreezeDuration = (int)(SystemClock.elapsedRealtime()
-                        - mDisplayFreezeTime);
-            }
+            win.reportResized();
             mResizingWindows.remove(i);
         }
 
@@ -9358,12 +9449,16 @@
                     }
                 }
             }
+        }
 
-            // Time to remove any exiting applications?
-            AppTokenList exitingAppTokens = displayContent.mExitingAppTokens;
+        // Time to remove any exiting applications?
+        for (int stackNdx = mStackIdToStack.size() - 1; stackNdx >= 0; --stackNdx) {
+            // Initialize state of exiting applications.
+            final AppTokenList exitingAppTokens =
+                    mStackIdToStack.valueAt(stackNdx).mExitingAppTokens;
             for (i = exitingAppTokens.size() - 1; i >= 0; i--) {
                 AppWindowToken token = exitingAppTokens.get(i);
-                if (!token.hasVisible && !mClosingApps.contains(token)) {
+                if (!token.hasVisible && !mClosingApps.contains(token) && !token.mDeferRemoval) {
                     // Make sure there is no animation running on this token,
                     // so any windows associated with it will be removed as
                     // soon as their animations are complete
@@ -9371,10 +9466,7 @@
                     token.mAppAnimator.animating = false;
                     if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
                             "performLayout: App token exiting now removed" + token);
-                    final Task task = mTaskIdToTask.get(token.groupId);
-                    if (task != null && task.removeAppToken(token)) {
-                        mTaskIdToTask.delete(token.groupId);
-                    }
+                    removeAppFromTaskLocked(token);
                     exitingAppTokens.remove(i);
                 }
             }
@@ -9409,18 +9501,18 @@
         setHoldScreenLocked(mInnerFields.mHoldScreen);
         if (!mDisplayFrozen) {
             if (mInnerFields.mScreenBrightness < 0 || mInnerFields.mScreenBrightness > 1.0f) {
-                mPowerManager.setScreenBrightnessOverrideFromWindowManager(-1);
+                mPowerManagerInternal.setScreenBrightnessOverrideFromWindowManager(-1);
             } else {
-                mPowerManager.setScreenBrightnessOverrideFromWindowManager(
+                mPowerManagerInternal.setScreenBrightnessOverrideFromWindowManager(
                         toBrightnessOverride(mInnerFields.mScreenBrightness));
             }
             if (mInnerFields.mButtonBrightness < 0 || mInnerFields.mButtonBrightness > 1.0f) {
-                mPowerManager.setButtonBrightnessOverrideFromWindowManager(-1);
+                mPowerManagerInternal.setButtonBrightnessOverrideFromWindowManager(-1);
             } else {
-                mPowerManager.setButtonBrightnessOverrideFromWindowManager(
+                mPowerManagerInternal.setButtonBrightnessOverrideFromWindowManager(
                         toBrightnessOverride(mInnerFields.mButtonBrightness));
             }
-            mPowerManager.setUserActivityTimeoutOverrideFromWindowManager(
+            mPowerManagerInternal.setUserActivityTimeoutOverrideFromWindowManager(
                     mInnerFields.mUserActivityTimeout);
         }
 
@@ -9455,8 +9547,9 @@
             for (i = 0; i < N; i++) {
                 WindowState w = mPendingRemoveTmp[i];
                 removeWindowInnerLocked(w.mSession, w);
-                if (!displayList.contains(w.mDisplayContent)) {
-                    displayList.add(w.mDisplayContent);
+                final DisplayContent displayContent = w.getDisplayContent();
+                if (displayContent != null && !displayList.contains(displayContent)) {
+                    displayList.add(displayContent);
                 }
             }
 
@@ -9466,6 +9559,11 @@
             }
         }
 
+        // Remove all deferred displays stacks, tasks, and activities.
+        for (int displayNdx = mDisplayContents.size() - 1; displayNdx >= 0; --displayNdx) {
+            mDisplayContents.valueAt(displayNdx).checkForDeferredActions();
+        }
+
         setFocusedStackFrame();
 
         // Check to see if we are now in a state where the screen should
@@ -9554,8 +9652,7 @@
         }
     }
 
-    @Override
-    public void requestTraversal() {
+    void requestTraversal() {
         synchronized (mWindowMap) {
             requestTraversalLocked();
         }
@@ -9945,6 +10042,7 @@
             }
 
             // TODO(multidisplay): rotation on main screen only.
+            displayContent.updateDisplayInfo();
             screenRotationAnimation = new ScreenRotationAnimation(mContext, displayContent,
                     mFxSession, inTransaction, mPolicy.isDefaultOrientationForced(), isSecure);
             mAnimator.setScreenRotationAnimationLocked(displayId, screenRotationAnimation);
@@ -10754,6 +10852,7 @@
     private DisplayContent newDisplayContentLocked(final Display display) {
         DisplayContent displayContent = new DisplayContent(display, this);
         final int displayId = display.getDisplayId();
+        if (DEBUG_DISPLAY) Slog.v(TAG, "Adding display=" + display);
         mDisplayContents.put(displayId, displayContent);
 
         DisplayInfo displayInfo = displayContent.getDisplayInfo();
@@ -10764,7 +10863,7 @@
             displayInfo.overscanTop = rect.top;
             displayInfo.overscanRight = rect.right;
             displayInfo.overscanBottom = rect.bottom;
-            mDisplayManagerService.setDisplayInfoOverrideFromWindowManager(
+            mDisplayManagerInternal.setDisplayInfoOverrideFromWindowManager(
                     displayId, displayInfo);
         }
         configureDisplayPolicyLocked(displayContent);
@@ -10834,20 +10933,20 @@
         return displayContent != null ? displayContent.getWindowList() : null;
     }
 
-    @Override
     public void onDisplayAdded(int displayId) {
         mH.sendMessage(mH.obtainMessage(H.DO_DISPLAY_ADDED, displayId, 0));
     }
 
-    private void handleDisplayAddedLocked(int displayId) {
-        final Display display = mDisplayManager.getDisplay(displayId);
-        if (display != null) {
-            createDisplayContentLocked(display);
-            displayReady(displayId);
+    public void handleDisplayAdded(int displayId) {
+        synchronized (mWindowMap) {
+            final Display display = mDisplayManager.getDisplay(displayId);
+            if (display != null) {
+                createDisplayContentLocked(display);
+                displayReady(displayId);
+            }
         }
     }
 
-    @Override
     public void onDisplayRemoved(int displayId) {
         mH.sendMessage(mH.obtainMessage(H.DO_DISPLAY_REMOVED, displayId, 0));
     }
@@ -10855,21 +10954,20 @@
     private void handleDisplayRemovedLocked(int displayId) {
         final DisplayContent displayContent = getDisplayContentLocked(displayId);
         if (displayContent != null) {
+            if (displayContent.isAnimating()) {
+                displayContent.mDeferredRemoval = true;
+                return;
+            }
+            if (DEBUG_DISPLAY) Slog.v(TAG, "Removing display=" + displayContent);
             mDisplayContents.delete(displayId);
             displayContent.close();
             if (displayId == Display.DEFAULT_DISPLAY) {
                 unregisterPointerEventListener(displayContent.mTapDetector);
             }
-            WindowList windows = displayContent.getWindowList();
-            while (!windows.isEmpty()) {
-                final WindowState win = windows.get(windows.size() - 1);
-                removeWindowLocked(win.mSession, win, true);
-            }
         }
         mAnimator.removeDisplayLocked(displayId);
     }
 
-    @Override
     public void onDisplayChanged(int displayId) {
         mH.sendMessage(mH.obtainMessage(H.DO_DISPLAY_CHANGED, displayId, 0));
     }
@@ -10885,4 +10983,11 @@
     public Object getWindowManagerLock() {
         return mWindowMap;
     }
+
+    private final class LocalService extends WindowManagerInternal {
+        @Override
+        public void requestTraversalFromDisplayManager() {
+            requestTraversal();
+        }
+    }
 }
diff --git a/services/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
similarity index 91%
rename from services/java/com/android/server/wm/WindowState.java
rename to services/core/java/com/android/server/wm/WindowState.java
index 4d53cea..9f3415e 100644
--- a/services/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -16,8 +16,11 @@
 
 package com.android.server.wm;
 
-import static com.android.server.wm.WindowManagerService.DEBUG_VISIBILITY;
+import static com.android.server.wm.WindowManagerService.DEBUG_CONFIGURATION;
 import static com.android.server.wm.WindowManagerService.DEBUG_LAYOUT;
+import static com.android.server.wm.WindowManagerService.DEBUG_ORIENTATION;
+import static com.android.server.wm.WindowManagerService.DEBUG_RESIZE;
+import static com.android.server.wm.WindowManagerService.DEBUG_VISIBILITY;
 
 import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
@@ -29,7 +32,9 @@
 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
 
 import android.app.AppOpsManager;
+import android.os.Debug;
 import android.os.RemoteCallbackList;
+import android.os.SystemClock;
 import android.util.TimeUtils;
 import android.view.IWindowFocusObserver;
 import android.view.IWindowId;
@@ -370,19 +375,17 @@
                 mAttachedWindow.mChildWindows.add(this);
             } else {
                 for (int i = 0; i < children_size; i++) {
-                    WindowState child = (WindowState)mAttachedWindow.mChildWindows.get(i);
-                    if (this.mSubLayer < child.mSubLayer) {
+                    WindowState child = mAttachedWindow.mChildWindows.get(i);
+                    if (mSubLayer < child.mSubLayer) {
                         mAttachedWindow.mChildWindows.add(i, this);
                         break;
-                    } else if (this.mSubLayer > child.mSubLayer) {
+                    } else if (mSubLayer > child.mSubLayer) {
                         continue;
                     }
 
-                    if (this.mBaseLayer <= child.mBaseLayer) {
+                    if (mBaseLayer <= child.mBaseLayer) {
                         mAttachedWindow.mChildWindows.add(i, this);
                         break;
-                    } else {
-                        continue;
                     }
                 }
                 if (children_size == mAttachedWindow.mChildWindows.size()) {
@@ -463,8 +466,8 @@
         mHaveFrame = true;
 
         TaskStack stack = mAppToken != null ? getStack() : null;
-        if (stack != null && stack.hasSibling()) {
-            mContainingFrame.set(getStackBounds(stack));
+        if (stack != null && !stack.isFullscreen()) {
+            getStackBounds(stack, mContainingFrame);
             if (mUnderStatusBar) {
                 mContainingFrame.top = pf.top;
             }
@@ -593,9 +596,12 @@
         }
 
         if (mIsWallpaper && (fw != mFrame.width() || fh != mFrame.height())) {
-            final DisplayInfo displayInfo = mDisplayContent.getDisplayInfo();
-            mService.updateWallpaperOffsetLocked(this,
-                    displayInfo.logicalWidth, displayInfo.logicalHeight, false);
+            final DisplayContent displayContent = getDisplayContent();
+            if (displayContent != null) {
+                final DisplayInfo displayInfo = displayContent.getDisplayInfo();
+                mService.updateWallpaperOffsetLocked(this,
+                        displayInfo.logicalWidth, displayInfo.logicalHeight, false);
+            }
         }
 
         if (DEBUG_LAYOUT || WindowManagerService.localLOGV) Slog.v(TAG,
@@ -708,8 +714,16 @@
         return mOverscanInsetsChanged || mContentInsetsChanged || mVisibleInsetsChanged;
     }
 
+    public DisplayContent getDisplayContent() {
+        return mAppToken == null ? mDisplayContent : getStack().getDisplayContent();
+    }
+
     public int getDisplayId() {
-        return mDisplayContent.getDisplayId();
+        final DisplayContent displayContent = getDisplayContent();
+        if (displayContent == null) {
+            return -1;
+        }
+        return displayContent.getDisplayId();
     }
 
     TaskStack getStack() {
@@ -717,21 +731,28 @@
         if (wtoken != null) {
             Task task = mService.mTaskIdToTask.get(wtoken.groupId);
             if (task != null) {
-                return task.mStack;
+                if (task.mStack != null) {
+                    return task.mStack;
+                }
+                Slog.e(TAG, "getStack: mStack null for task=" + task);
+            } else {
+                Slog.e(TAG, "getStack: " + this + " couldn't find taskId=" + wtoken.groupId
+                    + " Callers=" + Debug.getCallers(4));
             }
         }
         return mDisplayContent.getHomeStack();
     }
 
-    Rect getStackBounds() {
-        return getStackBounds(getStack());
+    void getStackBounds(Rect bounds) {
+        getStackBounds(getStack(), bounds);
     }
 
-    private Rect getStackBounds(TaskStack stack) {
+    private void getStackBounds(TaskStack stack, Rect bounds) {
         if (stack != null) {
-            return stack.mStackBox.mBounds;
+            stack.getBounds(bounds);
+            return;
         }
-        return mFrame;
+        bounds.set(mFrame);
     }
 
     public long getInputDispatchingTimeoutNanos() {
@@ -1190,7 +1211,12 @@
 
     @Override
     public boolean isDefaultDisplay() {
-        return mDisplayContent.isDefaultDisplay;
+        final DisplayContent displayContent = getDisplayContent();
+        if (displayContent == null) {
+            // Only a window that was on a non-default display can be detached from it.
+            return false;
+        }
+        return getDisplayContent().isDefaultDisplay;
     }
 
     public void setShowToOwnerOnlyLocked(boolean showToOwnerOnly) {
@@ -1207,7 +1233,11 @@
                 && win.mAppToken != null && win.mAppToken.showWhenLocked) {
             // Save some cycles by not calling getDisplayInfo unless it is an application
             // window intended for all users.
-            final DisplayInfo displayInfo = win.mDisplayContent.getDisplayInfo();
+            final DisplayContent displayContent = win.getDisplayContent();
+            if (displayContent == null) {
+                return true;
+            }
+            final DisplayInfo displayInfo = displayContent.getDisplayInfo();
             if (win.mFrame.left <= 0 && win.mFrame.top <= 0
                     && win.mFrame.right >= displayInfo.appWidth
                     && win.mFrame.bottom >= displayInfo.appHeight) {
@@ -1249,7 +1279,8 @@
     }
 
     WindowList getWindowList() {
-        return mDisplayContent.getWindowList();
+        final DisplayContent displayContent = getDisplayContent();
+        return displayContent == null ? null : displayContent.getWindowList();
     }
 
     /**
@@ -1278,6 +1309,54 @@
         }
     }
 
+    void reportResized() {
+        try {
+            if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG, "Reporting new frame to " + this
+                    + ": " + mCompatFrame);
+            boolean configChanged = isConfigChanged();
+            if ((DEBUG_RESIZE || DEBUG_ORIENTATION || DEBUG_CONFIGURATION) && configChanged) {
+                Slog.i(TAG, "Sending new config to window " + this + ": "
+                        + mWinAnimator.mSurfaceW + "x" + mWinAnimator.mSurfaceH
+                        + " / " + mService.mCurConfiguration);
+            }
+            setConfiguration(mService.mCurConfiguration);
+            if (DEBUG_ORIENTATION && mWinAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING)
+                Slog.i(TAG, "Resizing " + this + " WITH DRAW PENDING");
+
+            final Rect frame = mFrame;
+            final Rect overscanInsets = mLastOverscanInsets;
+            final Rect contentInsets = mLastContentInsets;
+            final Rect visibleInsets = mLastVisibleInsets;
+            final boolean reportDraw = mWinAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING;
+            final Configuration newConfig = configChanged ? mConfiguration : null;
+            if (mClient instanceof IWindow.Stub) {
+                // To prevent deadlock simulate one-way call if win.mClient is a local object.
+                mService.mH.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        try {
+                            mClient.resized(frame, overscanInsets, contentInsets,
+                                    visibleInsets, reportDraw, newConfig);
+                        } catch (RemoteException e) {
+                            // Not a remote call, RemoteException won't be raised.
+                        }
+                    }
+                });
+            } else {
+                mClient.resized(frame, overscanInsets, contentInsets, visibleInsets, reportDraw,
+                        newConfig);
+            }
+            mOverscanInsetsChanged = false;
+            mContentInsetsChanged = false;
+            mVisibleInsetsChanged = false;
+            mWinAnimator.mSurfaceResized = false;
+        } catch (RemoteException e) {
+            mOrientationChanging = false;
+            mLastFreezeDuration = (int)(SystemClock.elapsedRealtime()
+                    - mService.mDisplayFreezeTime);
+        }
+    }
+
     public void registerFocusObserver(IWindowFocusObserver observer) {
         synchronized(mService.mWindowMap) {
             if (mFocusCallbacks == null) {
@@ -1302,7 +1381,7 @@
     }
 
     void dump(PrintWriter pw, String prefix, boolean dumpAll) {
-        pw.print(prefix); pw.print("mDisplayId="); pw.print(mDisplayContent.getDisplayId());
+        pw.print(prefix); pw.print("mDisplayId="); pw.print(getDisplayId());
                 pw.print(" mSession="); pw.print(mSession);
                 pw.print(" mClient="); pw.println(mClient.asBinder());
         pw.print(prefix); pw.print("mOwnerUid="); pw.print(mOwnerUid);
diff --git a/services/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
similarity index 94%
rename from services/java/com/android/server/wm/WindowStateAnimator.java
rename to services/core/java/com/android/server/wm/WindowStateAnimator.java
index c405170..1ff0afb 100644
--- a/services/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -1,4 +1,18 @@
-// Copyright 2012 Google Inc. All Rights Reserved.
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 
 package com.android.server.wm;
 
@@ -150,8 +164,6 @@
     int mAttrFlags;
     int mAttrType;
 
-    final int mLayerStack;
-
     public WindowStateAnimator(final WindowState win) {
         final WindowManagerService service = win.mService;
 
@@ -159,9 +171,15 @@
         mAnimator = service.mAnimator;
         mPolicy = service.mPolicy;
         mContext = service.mContext;
-        final DisplayInfo displayInfo = win.mDisplayContent.getDisplayInfo();
-        mAnimDw = displayInfo.appWidth;
-        mAnimDh = displayInfo.appHeight;
+        final DisplayContent displayContent = win.getDisplayContent();
+        if (displayContent != null) {
+            final DisplayInfo displayInfo = displayContent.getDisplayInfo();
+            mAnimDw = displayInfo.appWidth;
+            mAnimDh = displayInfo.appHeight;
+        } else {
+            Slog.w(TAG, "WindowStateAnimator ctor: Display has been removed");
+            // This is checked on return and dealt with.
+        }
 
         mWin = win;
         mAttachedWinAnimator = win.mAttachedWindow == null
@@ -171,7 +189,6 @@
         mAttrFlags = win.mAttrs.flags;
         mAttrType = win.mAttrs.type;
         mIsWallpaper = win.mIsWallpaper;
-        mLayerStack = win.mDisplayContent.getDisplay().getLayerStack();
     }
 
     public void setAnimation(Animation anim) {
@@ -243,7 +260,8 @@
         // Save the animation state as it was before this step so WindowManagerService can tell if
         // we just started or just stopped animating by comparing mWasAnimating with isAnimating().
         mWasAnimating = mAnimating;
-        if (mService.okToDisplay()) {
+        final DisplayContent displayContent = mWin.getDisplayContent();
+        if (displayContent != null && mService.okToDisplay()) {
             // We will run animations as long as the display isn't frozen.
 
             if (mWin.isDrawnLw() && mAnimation != null) {
@@ -258,7 +276,7 @@
                         " scale=" + mService.mWindowAnimationScale);
                     mAnimation.initialize(mWin.mFrame.width(), mWin.mFrame.height(),
                             mAnimDw, mAnimDh);
-                    final DisplayInfo displayInfo = mWin.mDisplayContent.getDisplayInfo();
+                    final DisplayInfo displayInfo = displayContent.getDisplayInfo();
                     mAnimDw = displayInfo.appWidth;
                     mAnimDh = displayInfo.appHeight;
                     mAnimation.setStartTime(currentTime);
@@ -337,7 +355,9 @@
                         + mWin.mPolicyVisibilityAfterAnim);
             }
             mWin.mPolicyVisibility = mWin.mPolicyVisibilityAfterAnim;
-            mWin.mDisplayContent.layoutNeeded = true;
+            if (displayContent != null) {
+                displayContent.layoutNeeded = true;
+            }
             if (!mWin.mPolicyVisibility) {
                 if (mService.mCurrentFocus == mWin) {
                     if (WindowManagerService.DEBUG_FOCUS_LIGHT) Slog.i(TAG,
@@ -363,11 +383,13 @@
         } else if (mAttrType == LayoutParams.TYPE_STATUS_BAR && mWin.mPolicyVisibility) {
             // Upon completion of a not-visible to visible status bar animation a relayout is
             // required.
-            mWin.mDisplayContent.layoutNeeded = true;
+            if (displayContent != null) {
+                displayContent.layoutNeeded = true;
+            }
         }
 
         finishExit();
-        final int displayId = mWin.mDisplayContent.getDisplayId();
+        final int displayId = mWin.getDisplayId();
         mAnimator.setPendingLayoutChanges(displayId, WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM);
         if (WindowManagerService.DEBUG_LAYOUT_REPEATS) mService.debugLayoutRepeats(
                 "WindowStateAnimator", mAnimator.getPendingLayoutChanges(displayId));
@@ -487,6 +509,7 @@
         private final Rect mWindowCrop = new Rect();
         private boolean mShown = false;
         private int mLayerStack;
+        private boolean mIsOpaque;
         private final String mName;
 
         public SurfaceTrace(SurfaceSession s,
@@ -572,6 +595,16 @@
         }
 
         @Override
+        public void setOpaque(boolean isOpaque) {
+            if (isOpaque != mIsOpaque) {
+                Slog.v(SURFACE_TAG, "setOpaque(" + isOpaque + "): OLD:" + this
+                        + ". Called by " + Debug.getCallers(3));
+                mIsOpaque = isOpaque;
+            }
+            super.setOpaque(isOpaque);
+        }
+
+        @Override
         public void hide() {
             if (mShown) {
                 Slog.v(SURFACE_TAG, "hide: OLD:" + this + ". Called by " + Debug.getCallers(3));
@@ -617,7 +650,8 @@
                     + mName + " (" + mLayerStack + "): shown=" + mShown + " layer=" + mLayer
                     + " alpha=" + mSurfaceTraceAlpha + " " + mPosition.x + "," + mPosition.y
                     + " " + mSize.x + "x" + mSize.y
-                    + " crop=" + mWindowCrop.toShortString();
+                    + " crop=" + mWindowCrop.toShortString()
+                    + " opaque=" + mIsOpaque;
         }
     }
 
@@ -732,7 +766,10 @@
                     mSurfaceY = mWin.mFrame.top + mWin.mYOffset;
                     mSurfaceControl.setPosition(mSurfaceX, mSurfaceY);
                     mSurfaceLayer = mAnimLayer;
-                    mSurfaceControl.setLayerStack(mLayerStack);
+                    final DisplayContent displayContent = mWin.getDisplayContent();
+                    if (displayContent != null) {
+                        mSurfaceControl.setLayerStack(displayContent.getDisplay().getLayerStack());
+                    }
                     mSurfaceControl.setLayer(mAnimLayer);
                     mSurfaceControl.setAlpha(0);
                     mSurfaceShown = false;
@@ -921,8 +958,7 @@
                 tmpMatrix.postConcat(screenRotationAnimation.getEnterTransformation().getMatrix());
             }
             //TODO (multidisplay): Magnification is supported only for the default display.
-            if (mService.mDisplayMagnifier != null
-                    && mWin.getDisplayId() == Display.DEFAULT_DISPLAY) {
+            if (mService.mDisplayMagnifier != null && displayId == Display.DEFAULT_DISPLAY) {
                 MagnificationSpec spec = mService.mDisplayMagnifier
                         .getMagnificationSpecForWindowLocked(mWin);
                 if (spec != null && !spec.isNop()) {
@@ -1002,7 +1038,7 @@
                 && mWin.mBaseLayer < mAnimator.mAboveUniverseLayer);
         MagnificationSpec spec = null;
         //TODO (multidisplay): Magnification is supported only for the default display.
-        if (mService.mDisplayMagnifier != null && mWin.getDisplayId() == Display.DEFAULT_DISPLAY) {
+        if (mService.mDisplayMagnifier != null && displayId == Display.DEFAULT_DISPLAY) {
             spec = mService.mDisplayMagnifier.getMagnificationSpecForWindowLocked(mWin);
         }
         if (applyUniverseTransformation || spec != null) {
@@ -1080,7 +1116,11 @@
 
     void updateSurfaceWindowCrop(final boolean recoveringMemory) {
         final WindowState w = mWin;
-        DisplayInfo displayInfo = w.mDisplayContent.getDisplayInfo();
+        final DisplayContent displayContent = w.getDisplayContent();
+        if (displayContent == null) {
+            return;
+        }
+        DisplayInfo displayInfo = displayContent.getDisplayInfo();
 
         // Need to recompute a new system decor rect each time.
         if ((w.mAttrs.flags & LayoutParams.FLAG_SCALED) != 0) {
@@ -1181,8 +1221,7 @@
                         "SIZE " + width + "x" + height, null);
                 mSurfaceResized = true;
                 mSurfaceControl.setSize(width, height);
-                final int displayId = w.mDisplayContent.getDisplayId();
-                mAnimator.setPendingLayoutChanges(displayId,
+                mAnimator.setPendingLayoutChanges(w.getDisplayId(),
                         WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER);
                 if ((w.mAttrs.flags & LayoutParams.FLAG_DIM_BEHIND) != 0) {
                     w.getStack().startDimmingIfNeeded(this);
@@ -1329,8 +1368,7 @@
             Slog.w(TAG, "setTransparentRegionHint: null mSurface after mHasSurface true");
             return;
         }
-        if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
-            ">>> OPEN TRANSACTION setTransparentRegion");
+        if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION setTransparentRegion");
         SurfaceControl.openTransaction();
         try {
             if (SHOW_TRANSACTIONS) WindowManagerService.logSurface(mWin,
@@ -1356,8 +1394,7 @@
                 // transformation is being applied by the animation.
                 return;
             }
-            if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
-                    ">>> OPEN TRANSACTION setWallpaperOffset");
+            if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION setWallpaperOffset");
             SurfaceControl.openTransaction();
             try {
                 if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(mWin,
@@ -1375,6 +1412,22 @@
         }
     }
 
+    void setOpaque(boolean isOpaque) {
+        if (mSurfaceControl == null) {
+            return;
+        }
+        if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION setOpaque");
+        SurfaceControl.openTransaction();
+        try {
+            if (SHOW_TRANSACTIONS) WindowManagerService.logSurface(mWin, "isOpaque=" + isOpaque,
+                    null);
+            mSurfaceControl.setOpaque(isOpaque);
+        } finally {
+            SurfaceControl.closeTransaction();
+            if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, "<<< CLOSE TRANSACTION setOpaque");
+        }
+    }
+
     // This must be called while inside a transaction.
     boolean performShowLocked() {
         if (mWin.isHiddenFromUserLocked()) {
@@ -1444,7 +1497,10 @@
                         // do a layout.  If called from within the transaction
                         // loop, this will cause it to restart with a new
                         // layout.
-                        c.mDisplayContent.layoutNeeded = true;
+                        final DisplayContent displayContent = c.getDisplayContent();
+                        if (displayContent != null) {
+                            displayContent.layoutNeeded = true;
+                        }
                     }
                 }
             }
diff --git a/services/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
similarity index 100%
rename from services/java/com/android/server/wm/WindowToken.java
rename to services/core/java/com/android/server/wm/WindowToken.java
diff --git a/services/core/jni/Android.mk b/services/core/jni/Android.mk
new file mode 100644
index 0000000..0843e94
--- /dev/null
+++ b/services/core/jni/Android.mk
@@ -0,0 +1,60 @@
+# This file is included by the top level services directory to collect source
+# files
+LOCAL_REL_DIR := core/jni
+
+LOCAL_SRC_FILES += \
+    $(LOCAL_REL_DIR)/com_android_server_AlarmManagerService.cpp \
+    $(LOCAL_REL_DIR)/com_android_server_AssetAtlasService.cpp \
+    $(LOCAL_REL_DIR)/com_android_server_connectivity_Vpn.cpp \
+    $(LOCAL_REL_DIR)/com_android_server_ConsumerIrService.cpp \
+    $(LOCAL_REL_DIR)/com_android_server_dreams_McuHal.cpp \
+    $(LOCAL_REL_DIR)/com_android_server_hdmi_HdmiCecService.cpp \
+    $(LOCAL_REL_DIR)/com_android_server_input_InputApplicationHandle.cpp \
+    $(LOCAL_REL_DIR)/com_android_server_input_InputManagerService.cpp \
+    $(LOCAL_REL_DIR)/com_android_server_input_InputWindowHandle.cpp \
+    $(LOCAL_REL_DIR)/com_android_server_lights_LightsService.cpp \
+    $(LOCAL_REL_DIR)/com_android_server_location_GpsLocationProvider.cpp \
+    $(LOCAL_REL_DIR)/com_android_server_location_FlpHardwareProvider.cpp \
+    $(LOCAL_REL_DIR)/com_android_server_power_PowerManagerService.cpp \
+    $(LOCAL_REL_DIR)/com_android_server_SerialService.cpp \
+    $(LOCAL_REL_DIR)/com_android_server_SystemServer.cpp \
+    $(LOCAL_REL_DIR)/com_android_server_UsbDeviceManager.cpp \
+    $(LOCAL_REL_DIR)/com_android_server_UsbHostManager.cpp \
+    $(LOCAL_REL_DIR)/com_android_server_VibratorService.cpp \
+    $(LOCAL_REL_DIR)/onload.cpp
+
+include external/stlport/libstlport.mk
+
+LOCAL_C_INCLUDES += \
+    $(JNI_H_INCLUDE) \
+    frameworks/base/services \
+    frameworks/base/libs \
+    frameworks/base/core/jni \
+    frameworks/native/services \
+    external/skia/include/core \
+    libcore/include \
+    libcore/include/libsuspend \
+	$(call include-path-for, libhardware)/hardware \
+	$(call include-path-for, libhardware_legacy)/hardware_legacy \
+
+LOCAL_SHARED_LIBRARIES += \
+    libandroid_runtime \
+    libandroidfw \
+    libbinder \
+    libcutils \
+    liblog \
+    libhardware \
+    libhardware_legacy \
+    libnativehelper \
+    libutils \
+    libui \
+    libinput \
+    libinputservice \
+    libsensorservice \
+    libskia \
+    libgui \
+    libusbhost \
+    libsuspend \
+    libEGL \
+    libGLESv2
+
diff --git a/services/jni/com_android_server_AlarmManagerService.cpp b/services/core/jni/com_android_server_AlarmManagerService.cpp
similarity index 100%
rename from services/jni/com_android_server_AlarmManagerService.cpp
rename to services/core/jni/com_android_server_AlarmManagerService.cpp
diff --git a/services/jni/com_android_server_AssetAtlasService.cpp b/services/core/jni/com_android_server_AssetAtlasService.cpp
similarity index 100%
rename from services/jni/com_android_server_AssetAtlasService.cpp
rename to services/core/jni/com_android_server_AssetAtlasService.cpp
diff --git a/services/jni/com_android_server_ConsumerIrService.cpp b/services/core/jni/com_android_server_ConsumerIrService.cpp
similarity index 100%
rename from services/jni/com_android_server_ConsumerIrService.cpp
rename to services/core/jni/com_android_server_ConsumerIrService.cpp
diff --git a/services/jni/com_android_server_SerialService.cpp b/services/core/jni/com_android_server_SerialService.cpp
similarity index 100%
rename from services/jni/com_android_server_SerialService.cpp
rename to services/core/jni/com_android_server_SerialService.cpp
diff --git a/services/jni/com_android_server_SystemServer.cpp b/services/core/jni/com_android_server_SystemServer.cpp
similarity index 100%
rename from services/jni/com_android_server_SystemServer.cpp
rename to services/core/jni/com_android_server_SystemServer.cpp
diff --git a/services/jni/com_android_server_UsbDeviceManager.cpp b/services/core/jni/com_android_server_UsbDeviceManager.cpp
similarity index 100%
rename from services/jni/com_android_server_UsbDeviceManager.cpp
rename to services/core/jni/com_android_server_UsbDeviceManager.cpp
diff --git a/services/jni/com_android_server_UsbHostManager.cpp b/services/core/jni/com_android_server_UsbHostManager.cpp
similarity index 100%
rename from services/jni/com_android_server_UsbHostManager.cpp
rename to services/core/jni/com_android_server_UsbHostManager.cpp
diff --git a/services/jni/com_android_server_VibratorService.cpp b/services/core/jni/com_android_server_VibratorService.cpp
similarity index 100%
rename from services/jni/com_android_server_VibratorService.cpp
rename to services/core/jni/com_android_server_VibratorService.cpp
diff --git a/services/jni/com_android_server_connectivity_Vpn.cpp b/services/core/jni/com_android_server_connectivity_Vpn.cpp
similarity index 100%
rename from services/jni/com_android_server_connectivity_Vpn.cpp
rename to services/core/jni/com_android_server_connectivity_Vpn.cpp
diff --git a/services/core/jni/com_android_server_dreams_McuHal.cpp b/services/core/jni/com_android_server_dreams_McuHal.cpp
new file mode 100644
index 0000000..a6d9297
--- /dev/null
+++ b/services/core/jni/com_android_server_dreams_McuHal.cpp
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "McuHal"
+
+//#define LOG_NDEBUG 0
+
+#include "JNIHelp.h"
+#include "jni.h"
+
+#include <ScopedUtfChars.h>
+#include <ScopedPrimitiveArray.h>
+
+#include <utils/Errors.h>
+#include <utils/Log.h>
+#include <hardware/mcu.h>
+
+namespace android {
+
+static jlong nativeOpen(JNIEnv* env, jclass clazz) {
+    mcu_module_t* module = NULL;
+    status_t err = hw_get_module(MCU_HARDWARE_MODULE_ID,
+            (hw_module_t const**)&module);
+    if (err) {
+        ALOGE("Couldn't load %s module (%s)", MCU_HARDWARE_MODULE_ID, strerror(-err));
+        return 0;
+    }
+
+    err = module->init(module);
+    if (err) {
+        ALOGE("Couldn't initialize %s module (%s)", MCU_HARDWARE_MODULE_ID, strerror(-err));
+        return 0;
+    }
+
+    return reinterpret_cast<jlong>(module);
+}
+
+static jbyteArray nativeSendMessage(JNIEnv* env, jclass clazz,
+        jlong ptr, jstring msgStr, jbyteArray argArray) {
+    mcu_module_t* module = reinterpret_cast<mcu_module_t*>(ptr);
+
+    ScopedUtfChars msg(env, msgStr);
+    ALOGV("Sending message %s to MCU", msg.c_str());
+
+    void* result = NULL;
+    size_t resultSize = 0;
+    status_t err;
+    if (argArray) {
+        ScopedByteArrayRO arg(env, argArray);
+        err = module->sendMessage(module, msg.c_str(), arg.get(), arg.size(),
+                &result, &resultSize);
+    } else {
+        err = module->sendMessage(module, msg.c_str(), NULL, 0, &result, &resultSize);
+    }
+    if (err) {
+        ALOGE("Couldn't send message to MCU (%s)", strerror(-err));
+        return NULL;
+    }
+
+    if (!result) {
+        return NULL;
+    }
+
+    jbyteArray resultArray = env->NewByteArray(resultSize);
+    if (resultArray) {
+        env->SetByteArrayRegion(resultArray, 0, resultSize, static_cast<jbyte*>(result));
+    }
+    free(result);
+    return resultArray;
+}
+
+static JNINativeMethod gMcuHalMethods[] = {
+    /* name, signature, funcPtr */
+    { "nativeOpen", "()J",
+            (void*) nativeOpen },
+    { "nativeSendMessage", "(JLjava/lang/String;[B)[B",
+            (void*) nativeSendMessage },
+};
+
+int register_android_server_dreams_McuHal(JNIEnv* env) {
+    int res = jniRegisterNativeMethods(env, "com/android/server/dreams/McuHal",
+            gMcuHalMethods, NELEM(gMcuHalMethods));
+    LOG_FATAL_IF(res < 0, "Unable to register native methods.");
+    return 0;
+}
+
+} /* namespace android */
diff --git a/services/core/jni/com_android_server_hdmi_HdmiCecService.cpp b/services/core/jni/com_android_server_hdmi_HdmiCecService.cpp
new file mode 100644
index 0000000..6e03993
--- /dev/null
+++ b/services/core/jni/com_android_server_hdmi_HdmiCecService.cpp
@@ -0,0 +1,756 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "HdmiCecJni"
+
+#define LOG_NDEBUG 1
+
+#include "ScopedPrimitiveArray.h"
+
+#include <string>
+#include <deque>
+#include <map>
+
+#include <android_runtime/AndroidRuntime.h>
+#include <android_runtime/Log.h>
+#include <hardware/hdmi_cec.h>
+
+namespace android {
+
+static struct {
+    jmethodID handleMessage;
+    jmethodID handleHotplug;
+    jmethodID getActiveSource;
+    jmethodID getLanguage;
+} gHdmiCecServiceClassInfo;
+
+#ifndef min
+#define min(a, b) ((a) > (b) ? (b) : (a))
+#endif
+
+class HdmiCecHandler {
+public:
+    enum HdmiCecError {
+        SUCCESS = 0,
+        FAILED = -1
+    };
+
+    // Data type to hold a CEC message or internal event data.
+    typedef union {
+        cec_message_t cec;
+        hotplug_event_t hotplug;
+    } queue_item_t;
+
+    // Entry used for message queue.
+    typedef std::pair<int, const queue_item_t> MessageEntry;
+
+    HdmiCecHandler(hdmi_cec_device_t* device, jobject callbacksObj);
+
+    void initialize();
+
+    // initialize individual logical device.
+    cec_logical_address_t initLogicalDevice(cec_device_type_t type);
+    void releaseLogicalDevice(cec_device_type_t type);
+
+    cec_logical_address_t getLogicalAddress(cec_device_type_t deviceType);
+    uint16_t getPhysicalAddress();
+    cec_device_type_t getDeviceType(cec_logical_address_t addr);
+    void queueMessage(const MessageEntry& message);
+    void queueOutgoingMessage(const cec_message_t& message);
+    void sendReportPhysicalAddress(cec_logical_address_t srcAddr);
+    void sendActiveSource(cec_logical_address_t srcAddr);
+    void sendFeatureAbort(cec_logical_address_t srcAddr, cec_logical_address_t dstAddr,
+            int opcode, int reason);
+    void sendCecVersion(cec_logical_address_t srcAddr, cec_logical_address_t dstAddr,
+            int version);
+    void sendDeviceVendorId(cec_logical_address_t srcAddr, cec_logical_address_t dstAddr);
+    void sendGiveDeviceVendorID(cec_logical_address_t srcAddr, cec_logical_address_t dstAddr);
+    void sendSetOsdName(cec_logical_address_t srcAddr, cec_logical_address_t dstAddr,
+            const char* name, size_t len);
+    void sendSetMenuLanguage(cec_logical_address_t srcAddr, cec_logical_address_t dstAddr);
+
+    void sendCecMessage(const cec_message_t& message);
+    void setOsdName(const char* name, size_t len);
+
+private:
+    enum {
+        EVENT_TYPE_RX,
+        EVENT_TYPE_TX,
+        EVENT_TYPE_HOTPLUG,
+        EVENT_TYPE_STANDBY
+    };
+
+    /*
+     * logical address pool for each device type.
+     */
+    static const cec_logical_address_t TV_ADDR_POOL[];
+    static const cec_logical_address_t PLAYBACK_ADDR_POOL[];
+    static const cec_logical_address_t RECORDER_ADDR_POOL[];
+    static const cec_logical_address_t TUNER_ADDR_POOL[];
+
+    static const unsigned int MAX_BUFFER_SIZE = 256;
+    static const uint16_t INVALID_PHYSICAL_ADDRESS = 0xFFFF;
+
+    static void onReceived(const hdmi_event_t* event, void* arg);
+    static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName);
+
+    void updatePhysicalAddress();
+    void updateLogicalAddress();
+
+    // Allocate logical address. The CEC standard recommends that we try to use the address
+    // we have ever used before, in case this is to allocate an address afte the cable is
+    // connected again. If preferredAddr is given a valid one (not CEC_ADDR_UNREGISTERED), then
+    // this method checks if the address is available first. If not, it tries other addresses
+    // int the address pool available for the given type.
+    cec_logical_address_t allocateLogicalAddress(cec_device_type_t type,
+            cec_logical_address_t preferredAddr);
+
+    // Send a CEC ping message. Returns true if successful.
+    bool sendPing(cec_logical_address_t addr);
+
+    // Return the pool of logical addresses that are used for a given device type.
+    // One of the addresses in the pool will be chosen in the allocation logic.
+    bool getLogicalAddressPool(cec_device_type_t type, const cec_logical_address_t** addrPool,
+            size_t* poolSize);
+
+    // Handles the message retrieved from internal message queue. The message can be
+    // for either rx or tx.
+    void dispatchMessage(const MessageEntry& message);
+    void processIncomingMessage(const cec_message_t& msg);
+
+    // Check the message before we pass it up to framework. If true, we proceed.
+    // otherwise do not propagate it.
+    bool precheckMessage(const cec_message_t& msg);
+
+    // Propagate the message up to Java layer.
+    void propagateMessage(const cec_message_t& msg);
+    void propagateHotplug(bool connected);
+
+    // Handles incoming <Request Active Source> message. If one of logical
+    // devices is active, it should reply with <Active Source> message.
+    void handleRequestActiveSource();
+    void handleGetOsdName(const cec_message_t& msg);
+    void handleGiveDeviceVendorID(const cec_message_t& msg);
+    void handleGetCECVersion(const cec_message_t& msg);
+    void handleGetMenuLanguage(const cec_message_t& msg);
+
+    // Internal thread for message queue handler
+    class HdmiThread : public Thread {
+    public:
+        HdmiThread(HdmiCecHandler* hdmiCecHandler, bool canCallJava) :
+            Thread(canCallJava),
+            mHdmiCecHandler(hdmiCecHandler) {
+        }
+    private:
+        virtual bool threadLoop() {
+            ALOGV("HdmiThread started");
+            AutoMutex _l(mHdmiCecHandler->mMessageQueueLock);
+            mHdmiCecHandler->mMessageQueueCondition.wait(mHdmiCecHandler->mMessageQueueLock);
+            /* Process all messages in the queue */
+            while (mHdmiCecHandler->mMessageQueue.size() > 0) {
+                MessageEntry entry = mHdmiCecHandler->mMessageQueue.front();
+                mHdmiCecHandler->dispatchMessage(entry);
+            }
+            return true;
+        }
+
+        HdmiCecHandler* mHdmiCecHandler;
+    };
+
+    // device type -> logical address mapping
+    std::map<cec_device_type_t, cec_logical_address_t> mLogicalDevices;
+
+    hdmi_cec_device_t* mDevice;
+    jobject mCallbacksObj;
+    Mutex mLock;
+    Mutex mMessageQueueLock;
+    Condition mMessageQueueCondition;
+    sp<HdmiThread> mMessageQueueHandler;
+
+    std::deque<MessageEntry> mMessageQueue;
+    uint16_t mPhysicalAddress;
+    std::string mOsdName;
+};
+
+    const cec_logical_address_t HdmiCecHandler::TV_ADDR_POOL[] = {
+        CEC_ADDR_TV,
+        CEC_ADDR_FREE_USE,
+    };
+
+    const cec_logical_address_t HdmiCecHandler::PLAYBACK_ADDR_POOL[] = {
+        CEC_ADDR_PLAYBACK_1,
+        CEC_ADDR_PLAYBACK_2,
+        CEC_ADDR_PLAYBACK_3
+    };
+
+    const cec_logical_address_t HdmiCecHandler::RECORDER_ADDR_POOL[] = {
+        CEC_ADDR_RECORDER_1,
+        CEC_ADDR_RECORDER_2,
+        CEC_ADDR_RECORDER_3
+    };
+
+    const cec_logical_address_t HdmiCecHandler::TUNER_ADDR_POOL[] = {
+        CEC_ADDR_TUNER_1,
+        CEC_ADDR_TUNER_2,
+        CEC_ADDR_TUNER_3,
+        CEC_ADDR_TUNER_4
+    };
+
+HdmiCecHandler::HdmiCecHandler(hdmi_cec_device_t* device, jobject callbacksObj) :
+    mDevice(device),
+    mCallbacksObj(callbacksObj) {
+}
+
+void HdmiCecHandler::initialize() {
+    mDevice->register_event_callback(mDevice, HdmiCecHandler::onReceived, this);
+    mMessageQueueHandler = new HdmiThread(this, true /* canCallJava */);
+    mMessageQueueHandler->run("MessageHandler");
+    updatePhysicalAddress();
+}
+
+uint16_t HdmiCecHandler::getPhysicalAddress() {
+    return mPhysicalAddress;
+}
+
+cec_logical_address_t HdmiCecHandler::initLogicalDevice(cec_device_type_t type) {
+    cec_logical_address addr = allocateLogicalAddress(type, CEC_ADDR_UNREGISTERED);
+    if (addr != CEC_ADDR_UNREGISTERED && !mDevice->add_logical_address(mDevice, addr)) {
+        mLogicalDevices.insert(std::pair<cec_device_type_t, cec_logical_address_t>(type, addr));
+
+        // Broadcast <Report Physical Address> when a new logical address was allocated to let
+        // other devices discover the new logical device and its logical - physical address
+        // association.
+        sendReportPhysicalAddress(addr);
+    }
+    return addr;
+}
+
+void HdmiCecHandler::releaseLogicalDevice(cec_device_type_t type) {
+    std::map<cec_device_type_t, cec_logical_address_t>::iterator it = mLogicalDevices.find(type);
+    if (it != mLogicalDevices.end()) {
+        mLogicalDevices.erase(it);
+    }
+    // TODO: remove the address monitored in HAL as well.
+}
+
+cec_logical_address_t HdmiCecHandler::getLogicalAddress(cec_device_type_t type) {
+    std::map<cec_device_type_t, cec_logical_address_t>::iterator it = mLogicalDevices.find(type);
+    if (it != mLogicalDevices.end()) {
+        return it->second;
+    }
+    return CEC_ADDR_UNREGISTERED;
+}
+
+cec_device_type_t HdmiCecHandler::getDeviceType(cec_logical_address_t addr) {
+    std::map<cec_device_type_t, cec_logical_address_t>::iterator it = mLogicalDevices.begin();
+    for (; it != mLogicalDevices.end(); ++it) {
+        if (it->second == addr) {
+            return it->first;
+        }
+    }
+    return CEC_DEVICE_INACTIVE;
+}
+
+void HdmiCecHandler::queueMessage(const MessageEntry& entry) {
+    AutoMutex _l(mMessageQueueLock);
+    if (mMessageQueue.size() <=  MAX_BUFFER_SIZE) {
+        mMessageQueue.push_back(entry);
+        mMessageQueueCondition.signal();
+    } else {
+        ALOGW("Queue is full! Message dropped.");
+    }
+}
+
+void HdmiCecHandler::queueOutgoingMessage(const cec_message_t& message) {
+    queue_item_t item;
+    item.cec = message;
+    MessageEntry entry = std::make_pair(EVENT_TYPE_TX, item);
+    queueMessage(entry);
+}
+
+void HdmiCecHandler::sendReportPhysicalAddress(cec_logical_address_t addr) {
+    if (mPhysicalAddress == INVALID_PHYSICAL_ADDRESS) {
+        ALOGE("Invalid physical address.");
+        return;
+    }
+    cec_device_type_t deviceType = getDeviceType(addr);
+    if (deviceType == CEC_DEVICE_INACTIVE) {
+        ALOGE("Invalid logical address: %d", addr);
+        return;
+    }
+
+    cec_message_t msg;
+    msg.initiator = addr;
+    msg.destination = CEC_ADDR_BROADCAST;
+    msg.length = 4;
+    msg.body[0] = CEC_MESSAGE_REPORT_PHYSICAL_ADDRESS;
+    msg.body[1] = (mPhysicalAddress >> 8) & 0xff;
+    msg.body[2] = mPhysicalAddress & 0xff;
+    msg.body[3] = deviceType;
+    queueOutgoingMessage(msg);
+}
+
+void HdmiCecHandler::sendActiveSource(cec_logical_address_t srcAddr) {
+    if (mPhysicalAddress == INVALID_PHYSICAL_ADDRESS) {
+        ALOGE("Error getting physical address.");
+        return;
+    }
+    cec_message_t msg;
+    msg.initiator = srcAddr;
+    msg.destination = CEC_ADDR_BROADCAST;
+    msg.length = 3;
+    msg.body[0] = CEC_MESSAGE_ACTIVE_SOURCE;
+    msg.body[1] = (mPhysicalAddress >> 8) & 0xff;
+    msg.body[2] = mPhysicalAddress & 0xff;
+    queueOutgoingMessage(msg);
+}
+
+void HdmiCecHandler::sendFeatureAbort(cec_logical_address_t srcAddr,
+        cec_logical_address_t dstAddr, int opcode, int reason) {
+    cec_message_t msg;
+    msg.initiator = srcAddr;
+    msg.destination = dstAddr;
+    msg.length = 3;
+    msg.body[0] = CEC_MESSAGE_FEATURE_ABORT;
+    msg.body[1] = opcode;
+    msg.body[2] = reason;
+    queueOutgoingMessage(msg);
+}
+
+void HdmiCecHandler::sendCecVersion(cec_logical_address_t srcAddr,
+        cec_logical_address_t dstAddr, int version) {
+    cec_message_t msg;
+    msg.initiator = srcAddr;
+    msg.destination = dstAddr;
+    msg.length = 2;
+    msg.body[0] = CEC_MESSAGE_CEC_VERSION;
+    msg.body[1] = version;
+    queueOutgoingMessage(msg);
+}
+
+void HdmiCecHandler::sendGiveDeviceVendorID(cec_logical_address_t srcAddr,
+        cec_logical_address_t dstAddr) {
+    cec_message_t msg;
+    msg.initiator = srcAddr;
+    msg.destination = dstAddr;
+    msg.length = 1;
+    msg.body[0] = CEC_MESSAGE_GIVE_DEVICE_VENDOR_ID;
+    queueOutgoingMessage(msg);
+}
+
+void HdmiCecHandler::sendDeviceVendorId(cec_logical_address_t srcAddr,
+        cec_logical_address_t dstAddr) {
+    cec_message_t msg;
+    msg.initiator = srcAddr;
+    msg.destination = dstAddr;
+    msg.length = 4;
+    msg.body[0] = CEC_MESSAGE_DEVICE_VENDOR_ID;
+    uint32_t vendor_id;
+    mDevice->get_vendor_id(mDevice, &vendor_id);
+    msg.body[1] = (vendor_id >> 16) & 0xff;
+    msg.body[2] = (vendor_id >> 8) & 0xff;
+    msg.body[3] = vendor_id & 0xff;
+    queueOutgoingMessage(msg);
+}
+
+void HdmiCecHandler::sendSetOsdName(cec_logical_address_t srcAddr, cec_logical_address_t dstAddr,
+        const char* name, size_t len) {
+    cec_message_t msg;
+    msg.initiator = srcAddr;
+    msg.destination = dstAddr;
+    msg.body[0] = CEC_MESSAGE_SET_OSD_NAME;
+    msg.length = min(len + 1, CEC_MESSAGE_BODY_MAX_LENGTH);
+    std::memcpy(msg.body + 1, name, msg.length - 1);
+    queueOutgoingMessage(msg);
+}
+
+void HdmiCecHandler::sendSetMenuLanguage(cec_logical_address_t srcAddr,
+        cec_logical_address_t dstAddr) {
+    char lang[4];   // buffer for 3-letter language code
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    jstring res = (jstring) env->CallObjectMethod(mCallbacksObj,
+            gHdmiCecServiceClassInfo.getLanguage,
+            getDeviceType(srcAddr));
+    const char *clang = env->GetStringUTFChars(res, NULL);
+    strlcpy(lang, clang, sizeof(lang));
+    env->ReleaseStringUTFChars(res, clang);
+
+    cec_message_t msg;
+    msg.initiator = srcAddr;
+    msg.destination = dstAddr;
+    msg.length = 4;  // opcode (1) + language code (3)
+    msg.body[0] = CEC_MESSAGE_SET_MENU_LANGUAGE;
+    std::memcpy(msg.body + 1, lang, 3);
+    queueOutgoingMessage(msg);
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+}
+
+void HdmiCecHandler::sendCecMessage(const cec_message_t& message) {
+    AutoMutex _l(mLock);
+    ALOGV("sendCecMessage");
+    mDevice->send_message(mDevice, &message);
+}
+
+void HdmiCecHandler::setOsdName(const char* name, size_t len) {
+    mOsdName.assign(name, min(len, CEC_MESSAGE_BODY_MAX_LENGTH - 1));
+}
+
+// static
+void HdmiCecHandler::onReceived(const hdmi_event_t* event, void* arg) {
+    HdmiCecHandler* handler = static_cast<HdmiCecHandler*>(arg);
+    if (handler == NULL) {
+        return;
+    }
+    queue_item_t item;
+    if (event->type == HDMI_EVENT_CEC_MESSAGE) {
+        item.cec = event->cec;
+        MessageEntry entry = std::make_pair<int, const queue_item_t>(EVENT_TYPE_RX, item);
+        handler->queueMessage(entry);
+    } else if (event->type == HDMI_EVENT_HOT_PLUG) {
+        item.hotplug = event->hotplug;
+        MessageEntry entry = std::make_pair<int, const queue_item_t>(EVENT_TYPE_HOTPLUG, item);
+        handler->queueMessage(entry);
+    }
+}
+
+// static
+void HdmiCecHandler::checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
+    if (env->ExceptionCheck()) {
+        ALOGE("An exception was thrown by callback '%s'.", methodName);
+        LOGE_EX(env);
+        env->ExceptionClear();
+    }
+}
+
+void HdmiCecHandler::updatePhysicalAddress() {
+    uint16_t addr;
+    if (!mDevice->get_physical_address(mDevice, &addr)) {
+        mPhysicalAddress = addr;
+    } else {
+        mPhysicalAddress = INVALID_PHYSICAL_ADDRESS;
+    }
+}
+
+void HdmiCecHandler::updateLogicalAddress() {
+    mDevice->clear_logical_address(mDevice);
+    std::map<cec_device_type_t, cec_logical_address_t>::iterator it = mLogicalDevices.begin();
+    for (; it != mLogicalDevices.end(); ++it) {
+        cec_logical_address_t addr;
+        cec_logical_address_t preferredAddr = it->second;
+        cec_device_type_t deviceType = it->first;
+        addr = allocateLogicalAddress(deviceType, preferredAddr);
+        if (!mDevice->add_logical_address(mDevice, addr)) {
+            it->second = addr;
+        } else {
+            it->second = CEC_ADDR_UNREGISTERED;
+        }
+    }
+}
+
+cec_logical_address_t HdmiCecHandler::allocateLogicalAddress(cec_device_type_t type,
+        cec_logical_address_t preferredAddr) {
+    const cec_logical_address_t* addrPool;
+    size_t poolSize;
+    if (getLogicalAddressPool(type, &addrPool, &poolSize) < 0) {
+        return CEC_ADDR_UNREGISTERED;
+    }
+    unsigned start = 0;
+
+    // Find the index of preferred address in the pool. If not found, the start
+    // position will be 0. This happens when the passed preferredAddr is set to
+    // CEC_ADDR_UNREGISTERED, meaning that no preferred address is given.
+    for (unsigned i = 0; i < poolSize; i++) {
+        if (addrPool[i] == preferredAddr) {
+            start = i;
+            break;
+        }
+    }
+    for (unsigned i = 0; i < poolSize; i++) {
+        cec_logical_address_t addr = addrPool[(start + i) % poolSize];
+        if (!sendPing(addr)) {
+            // Failure in pinging means the address is available, not taken by any device.
+            ALOGV("Logical Address Allocation success: %d", addr);
+            return addr;
+        }
+    }
+    ALOGE("Logical Address Allocation failed");
+    return CEC_ADDR_UNREGISTERED;
+}
+
+bool HdmiCecHandler::sendPing(cec_logical_address addr) {
+    cec_message_t msg;
+    msg.initiator = msg.destination = addr;
+    msg.length = 0;
+    return !mDevice->send_message(mDevice, &msg);
+
+}
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+bool HdmiCecHandler::getLogicalAddressPool(cec_device_type_t deviceType,
+        const cec_logical_address_t** addrPool, size_t* poolSize) {
+    switch (deviceType) {
+    case CEC_DEVICE_TV:
+        *addrPool = TV_ADDR_POOL;
+        *poolSize = ARRAY_SIZE(TV_ADDR_POOL);
+        break;
+    case CEC_DEVICE_RECORDER:
+        *addrPool = RECORDER_ADDR_POOL;
+        *poolSize = ARRAY_SIZE(RECORDER_ADDR_POOL);
+        break;
+    case CEC_DEVICE_TUNER:
+        *addrPool = TUNER_ADDR_POOL;
+        *poolSize = ARRAY_SIZE(TUNER_ADDR_POOL);
+        break;
+    case CEC_DEVICE_PLAYBACK:
+        *addrPool = PLAYBACK_ADDR_POOL;
+        *poolSize = ARRAY_SIZE(PLAYBACK_ADDR_POOL);
+        break;
+    default:
+        ALOGE("Unsupported device type: %d", deviceType);
+        return false;
+    }
+    return true;
+}
+
+#undef ARRAY_SIZE
+
+void HdmiCecHandler::dispatchMessage(const MessageEntry& entry) {
+    int type = entry.first;
+    mMessageQueueLock.unlock();
+    if (type == EVENT_TYPE_RX) {
+        mMessageQueue.pop_front();
+        processIncomingMessage(entry.second.cec);
+    } else if (type == EVENT_TYPE_TX) {
+        sendCecMessage(entry.second.cec);
+        mMessageQueue.pop_front();
+    } else if (type == EVENT_TYPE_HOTPLUG) {
+        mMessageQueue.pop_front();
+        bool connected = entry.second.hotplug.connected;
+        if (connected) {
+            updatePhysicalAddress();
+            updateLogicalAddress();
+        }
+        propagateHotplug(connected);
+    }
+    mMessageQueueLock.lock();
+}
+
+void HdmiCecHandler::processIncomingMessage(const cec_message_t& msg) {
+    int opcode = msg.body[0];
+    if (opcode == CEC_MESSAGE_GIVE_PHYSICAL_ADDRESS) {
+        sendReportPhysicalAddress(msg.destination);
+    } else if (opcode == CEC_MESSAGE_REQUEST_ACTIVE_SOURCE) {
+        handleRequestActiveSource();
+    } else if (opcode == CEC_MESSAGE_GET_OSD_NAME) {
+        handleGetOsdName(msg);
+    } else if (opcode == CEC_MESSAGE_GIVE_DEVICE_VENDOR_ID) {
+        handleGiveDeviceVendorID(msg);
+    } else if (opcode == CEC_MESSAGE_GET_CEC_VERSION) {
+        handleGetCECVersion(msg);
+    } else if (opcode == CEC_MESSAGE_GET_MENU_LANGUAGE) {
+        handleGetMenuLanguage(msg);
+    } else if (opcode == CEC_MESSAGE_ABORT) {
+        // Compliance testing requires that abort message be responded with feature abort.
+        sendFeatureAbort(msg.destination, msg.initiator, msg.body[0], ABORT_REFUSED);
+    } else {
+        if (precheckMessage(msg)) {
+            propagateMessage(msg);
+        }
+    }
+}
+
+bool HdmiCecHandler::precheckMessage(const cec_message_t& msg) {
+    // Check if this is the broadcast message coming to itself, which need not be passed
+    // back to framework. This happens because CEC spec specifies that a physical device
+    // may host multiple logical devices. A broadcast message sent by one of them therefore
+    // should be able to reach the others by the loopback mechanism.
+    //
+    // Currently we don't deal with multiple logical devices, so this is not necessary.
+    // It should be revisited once we support hosting multiple logical devices.
+    int opcode = msg.body[0];
+    if (msg.destination == CEC_ADDR_BROADCAST &&
+            (opcode == CEC_MESSAGE_ACTIVE_SOURCE ||
+             opcode == CEC_MESSAGE_SET_STREAM_PATH ||
+             opcode == CEC_MESSAGE_INACTIVE_SOURCE)) {
+        uint16_t senderAddr = (msg.body[1] << 8) + msg.body[2];
+        if (senderAddr == mPhysicalAddress) {
+            return false;
+        }
+    }
+    return true;
+}
+
+void HdmiCecHandler::propagateMessage(const cec_message_t& msg) {
+    int paramLen = msg.length - 1;
+    jint srcAddr = msg.initiator;
+    jint dstAddr = msg.destination;
+    jint opcode = msg.body[0];
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    jbyteArray params = env->NewByteArray(paramLen);
+    const jbyte* body = reinterpret_cast<const jbyte *>(msg.body + 1);
+    if (paramLen > 0) {
+        env->SetByteArrayRegion(params, 0, paramLen, body);
+    }
+    env->CallVoidMethod(mCallbacksObj,
+            gHdmiCecServiceClassInfo.handleMessage,
+            srcAddr, dstAddr, opcode, params);
+    env->DeleteLocalRef(params);
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+}
+
+void HdmiCecHandler::propagateHotplug(bool connected) {
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    env->CallVoidMethod(mCallbacksObj,
+            gHdmiCecServiceClassInfo.handleHotplug,
+            connected);
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+}
+
+
+void HdmiCecHandler::handleRequestActiveSource() {
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    jint activeDeviceType = env->CallIntMethod(mCallbacksObj,
+            gHdmiCecServiceClassInfo.getActiveSource);
+    if (activeDeviceType != CEC_DEVICE_INACTIVE) {
+        sendActiveSource(getLogicalAddress(static_cast<cec_device_type_t>(activeDeviceType)));
+    }
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+}
+
+void HdmiCecHandler::handleGetOsdName(const cec_message_t& msg) {
+    if (!mOsdName.empty()) {
+        sendSetOsdName(msg.destination, msg.initiator, mOsdName.c_str(), mOsdName.length());
+    }
+}
+
+void HdmiCecHandler::handleGiveDeviceVendorID(const cec_message_t& msg) {
+    sendDeviceVendorId(msg.destination, msg.initiator);
+}
+
+void HdmiCecHandler::handleGetCECVersion(const cec_message_t& msg) {
+    int version;
+    mDevice->get_version(mDevice, &version);
+    sendCecVersion(msg.destination, msg.initiator, version);
+}
+
+void HdmiCecHandler::handleGetMenuLanguage(const cec_message_t& msg) {
+    sendSetMenuLanguage(msg.destination, msg.initiator);
+}
+
+//------------------------------------------------------------------------------
+
+#define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \
+        var = env->GetMethodID(clazz, methodName, methodDescriptor); \
+        LOG_FATAL_IF(! var, "Unable to find method " methodName);
+
+static jlong nativeInit(JNIEnv* env, jclass clazz, jobject callbacksObj) {
+    int err;
+    hw_module_t* module;
+    err = hw_get_module(HDMI_CEC_HARDWARE_MODULE_ID, const_cast<const hw_module_t **>(&module));
+    if (err != 0) {
+        ALOGE("Error acquiring hardware module: %d", err);
+        return 0;
+    }
+    hw_device_t* device;
+    err = module->methods->open(module, HDMI_CEC_HARDWARE_INTERFACE, &device);
+    if (err != 0) {
+        ALOGE("Error opening hardware module: %d", err);
+        return 0;
+    }
+    HdmiCecHandler *handler = new HdmiCecHandler(reinterpret_cast<hdmi_cec_device *>(device),
+            env->NewGlobalRef(callbacksObj));
+    handler->initialize();
+
+    GET_METHOD_ID(gHdmiCecServiceClassInfo.handleMessage, clazz,
+            "handleMessage", "(III[B)V");
+    GET_METHOD_ID(gHdmiCecServiceClassInfo.handleHotplug, clazz,
+            "handleHotplug", "(Z)V");
+    GET_METHOD_ID(gHdmiCecServiceClassInfo.getActiveSource, clazz,
+            "getActiveSource", "()I");
+    GET_METHOD_ID(gHdmiCecServiceClassInfo.getLanguage, clazz,
+            "getLanguage", "(I)Ljava/lang/String;");
+
+    return reinterpret_cast<jlong>(handler);
+}
+
+static void nativeSendMessage(JNIEnv* env, jclass clazz, jlong handlerPtr, jint deviceType,
+        jint dstAddr, jint opcode, jbyteArray params) {
+    HdmiCecHandler *handler = reinterpret_cast<HdmiCecHandler *>(handlerPtr);
+    cec_logical_address_t srcAddr = handler->getLogicalAddress(
+            static_cast<cec_device_type_t>(deviceType));
+    jsize len = env->GetArrayLength(params);
+    ScopedByteArrayRO paramsPtr(env, params);
+    cec_message_t message;
+    message.initiator = srcAddr;
+    message.destination = static_cast<cec_logical_address_t>(dstAddr);
+    message.length = min(len + 1, CEC_MESSAGE_BODY_MAX_LENGTH);
+    message.body[0] = opcode;
+    std::memcpy(message.body + 1, paramsPtr.get(), message.length - 1);
+    handler->sendCecMessage(message);
+}
+
+static jint nativeAllocateLogicalAddress(JNIEnv* env, jclass clazz, jlong handlerPtr,
+        jint deviceType) {
+    HdmiCecHandler *handler = reinterpret_cast<HdmiCecHandler *>(handlerPtr);
+    return handler->initLogicalDevice(static_cast<cec_device_type_t>(deviceType));
+}
+
+static void nativeRemoveLogicalAddress(JNIEnv* env, jclass clazz, jlong handlerPtr,
+       jint deviceType) {
+    HdmiCecHandler *handler = reinterpret_cast<HdmiCecHandler *>(handlerPtr);
+    return handler->releaseLogicalDevice(static_cast<cec_device_type_t>(deviceType));
+}
+
+static jint nativeGetPhysicalAddress(JNIEnv* env, jclass clazz, jlong handlerPtr) {
+    HdmiCecHandler *handler = reinterpret_cast<HdmiCecHandler *>(handlerPtr);
+    return handler->getPhysicalAddress();
+}
+
+static void nativeSetOsdName(JNIEnv* env, jclass clazz, jlong handlerPtr, jbyteArray name) {
+    HdmiCecHandler *handler = reinterpret_cast<HdmiCecHandler *>(handlerPtr);
+    jsize len = env->GetArrayLength(name);
+    if (len > 0) {
+        ScopedByteArrayRO namePtr(env, name);
+        handler->setOsdName(reinterpret_cast<const char *>(namePtr.get()), len);
+    }
+}
+
+static JNINativeMethod sMethods[] = {
+    /* name, signature, funcPtr */
+    { "nativeInit", "(Lcom/android/server/hdmi/HdmiCecService;)J",
+            (void *)nativeInit },
+    { "nativeSendMessage", "(JIII[B)V",
+            (void *)nativeSendMessage },
+    { "nativeAllocateLogicalAddress", "(JI)I",
+            (void *)nativeAllocateLogicalAddress },
+    { "nativeRemoveLogicalAddress", "(JI)V",
+            (void *)nativeRemoveLogicalAddress },
+    { "nativeGetPhysicalAddress", "(J)I",
+            (void *)nativeGetPhysicalAddress },
+    { "nativeSetOsdName", "(J[B)V",
+            (void *)nativeSetOsdName },
+};
+
+#define CLASS_PATH "com/android/server/hdmi/HdmiCecService"
+
+int register_android_server_hdmi_HdmiCecService(JNIEnv* env) {
+    int res = jniRegisterNativeMethods(env, CLASS_PATH, sMethods, NELEM(sMethods));
+    LOG_FATAL_IF(res < 0, "Unable to register native methods.");
+    return 0;
+}
+
+}  /* namespace android */
diff --git a/services/jni/com_android_server_input_InputApplicationHandle.cpp b/services/core/jni/com_android_server_input_InputApplicationHandle.cpp
similarity index 100%
rename from services/jni/com_android_server_input_InputApplicationHandle.cpp
rename to services/core/jni/com_android_server_input_InputApplicationHandle.cpp
diff --git a/services/jni/com_android_server_input_InputApplicationHandle.h b/services/core/jni/com_android_server_input_InputApplicationHandle.h
similarity index 100%
rename from services/jni/com_android_server_input_InputApplicationHandle.h
rename to services/core/jni/com_android_server_input_InputApplicationHandle.h
diff --git a/services/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
similarity index 94%
rename from services/jni/com_android_server_input_InputManagerService.cpp
rename to services/core/jni/com_android_server_input_InputManagerService.cpp
index 10ad278..a4f4a0b 100644
--- a/services/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -69,7 +69,7 @@
     jmethodID notifyANR;
     jmethodID filterInputEvent;
     jmethodID interceptKeyBeforeQueueing;
-    jmethodID interceptMotionBeforeQueueingWhenScreenOff;
+    jmethodID interceptWakeMotionBeforeQueueing;
     jmethodID interceptKeyBeforeDispatching;
     jmethodID dispatchUnhandledKey;
     jmethodID checkInjectEventsPermission;
@@ -99,6 +99,12 @@
     jclass clazz;
 } gMotionEventClassInfo;
 
+static struct {
+    jclass clazz;
+    jmethodID constructor;
+} gInputDeviceIdentifierInfo;
+
+
 
 // --- Global functions ---
 
@@ -144,8 +150,6 @@
 
 enum {
     WM_ACTION_PASS_TO_USER = 1,
-    WM_ACTION_WAKE_UP = 2,
-    WM_ACTION_GO_TO_SLEEP = 4,
 };
 
 
@@ -177,13 +181,14 @@
     void setSystemUiVisibility(int32_t visibility);
     void setPointerSpeed(int32_t speed);
     void setShowTouches(bool enabled);
+    void setInteractive(bool interactive);
 
     /* --- InputReaderPolicyInterface implementation --- */
 
     virtual void getReaderConfiguration(InputReaderConfiguration* outConfig);
     virtual sp<PointerControllerInterface> obtainPointerController(int32_t deviceId);
     virtual void notifyInputDevicesChanged(const Vector<InputDeviceInfo>& inputDevices);
-    virtual sp<KeyCharacterMap> getKeyboardLayoutOverlay(const String8& inputDeviceDescriptor);
+    virtual sp<KeyCharacterMap> getKeyboardLayoutOverlay(const InputDeviceIdentifier& identifier);
     virtual String8 getDeviceAlias(const InputDeviceIdentifier& identifier);
 
     /* --- InputDispatcherPolicyInterface implementation --- */
@@ -197,7 +202,6 @@
     virtual void notifyInputChannelBroken(const sp<InputWindowHandle>& inputWindowHandle);
     virtual bool filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags);
     virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig);
-    virtual bool isKeyRepeatEnabled();
     virtual void interceptKeyBeforeQueueing(const KeyEvent* keyEvent, uint32_t& policyFlags);
     virtual void interceptMotionBeforeQueueing(nsecs_t when, uint32_t& policyFlags);
     virtual nsecs_t interceptKeyBeforeDispatching(
@@ -245,14 +249,12 @@
         wp<PointerController> pointerController;
     } mLocked;
 
+    volatile bool mInteractive;
+
     void updateInactivityTimeoutLocked(const sp<PointerController>& controller);
     void handleInterceptActions(jint wmActions, nsecs_t when, uint32_t& policyFlags);
     void ensureSpriteControllerLocked();
 
-    // Power manager interactions.
-    bool isScreenOn();
-    bool isScreenBright();
-
     static bool checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName);
 
     static inline JNIEnv* jniEnv() {
@@ -264,7 +266,7 @@
 
 NativeInputManager::NativeInputManager(jobject contextObj,
         jobject serviceObj, const sp<Looper>& looper) :
-        mLooper(looper) {
+        mLooper(looper), mInteractive(true) {
     JNIEnv* env = jniEnv();
 
     mContextObj = env->NewGlobalRef(contextObj);
@@ -492,13 +494,16 @@
 }
 
 sp<KeyCharacterMap> NativeInputManager::getKeyboardLayoutOverlay(
-        const String8& inputDeviceDescriptor) {
+        const InputDeviceIdentifier& identifier) {
     JNIEnv* env = jniEnv();
 
     sp<KeyCharacterMap> result;
-    ScopedLocalRef<jstring> descriptorObj(env, env->NewStringUTF(inputDeviceDescriptor.string()));
+    ScopedLocalRef<jstring> descriptor(env, env->NewStringUTF(identifier.descriptor.string()));
+    ScopedLocalRef<jobject> identifierObj(env, env->NewObject(gInputDeviceIdentifierInfo.clazz,
+            gInputDeviceIdentifierInfo.constructor, descriptor.get(),
+            identifier.vendor, identifier.product));
     ScopedLocalRef<jobjectArray> arrayObj(env, jobjectArray(env->CallObjectMethod(mServiceObj,
-                gServiceClassInfo.getKeyboardLayoutOverlay, descriptorObj.get())));
+                gServiceClassInfo.getKeyboardLayoutOverlay, identifierObj.get())));
     if (arrayObj.get()) {
         ScopedLocalRef<jstring> filenameObj(env,
                 jstring(env->GetObjectArrayElement(arrayObj.get(), 0)));
@@ -617,11 +622,6 @@
     }
 }
 
-bool NativeInputManager::isKeyRepeatEnabled() {
-    // Only enable automatic key repeating when the screen is on.
-    return isScreenOn();
-}
-
 void NativeInputManager::setInputWindows(JNIEnv* env, jobjectArray windowHandleObjArray) {
     Vector<sp<InputWindowHandle> > windowHandles;
 
@@ -733,12 +733,8 @@
             InputReaderConfiguration::CHANGE_SHOW_TOUCHES);
 }
 
-bool NativeInputManager::isScreenOn() {
-    return android_server_PowerManagerService_isScreenOn();
-}
-
-bool NativeInputManager::isScreenBright() {
-    return android_server_PowerManagerService_isScreenBright();
+void NativeInputManager::setInteractive(bool interactive) {
+    mInteractive = interactive;
 }
 
 bool NativeInputManager::filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags) {
@@ -779,18 +775,18 @@
     // - Ignore untrusted events and pass them along.
     // - Ask the window manager what to do with normal events and trusted injected events.
     // - For normal events wake and brighten the screen if currently off or dim.
+    if (mInteractive) {
+        policyFlags |= POLICY_FLAG_INTERACTIVE;
+    }
     if ((policyFlags & POLICY_FLAG_TRUSTED)) {
         nsecs_t when = keyEvent->getEventTime();
-        bool isScreenOn = this->isScreenOn();
-        bool isScreenBright = this->isScreenBright();
-
         JNIEnv* env = jniEnv();
         jobject keyEventObj = android_view_KeyEvent_fromNative(env, keyEvent);
         jint wmActions;
         if (keyEventObj) {
             wmActions = env->CallIntMethod(mServiceObj,
                     gServiceClassInfo.interceptKeyBeforeQueueing,
-                    keyEventObj, policyFlags, isScreenOn);
+                    keyEventObj, policyFlags);
             if (checkAndClearExceptionFromCallback(env, "interceptKeyBeforeQueueing")) {
                 wmActions = 0;
             }
@@ -801,16 +797,6 @@
             wmActions = 0;
         }
 
-        if (!(policyFlags & POLICY_FLAG_INJECTED)) {
-            if (!isScreenOn) {
-                policyFlags |= POLICY_FLAG_WOKE_HERE;
-            }
-
-            if (!isScreenBright) {
-                policyFlags |= POLICY_FLAG_BRIGHT_HERE;
-            }
-        }
-
         handleInterceptActions(wmActions, when, /*byref*/ policyFlags);
     } else {
         policyFlags |= POLICY_FLAG_PASS_TO_USER;
@@ -823,24 +809,22 @@
     // - No special filtering for injected events required at this time.
     // - Filter normal events based on screen state.
     // - For normal events brighten (but do not wake) the screen if currently dim.
+    if (mInteractive) {
+        policyFlags |= POLICY_FLAG_INTERACTIVE;
+    }
     if ((policyFlags & POLICY_FLAG_TRUSTED) && !(policyFlags & POLICY_FLAG_INJECTED)) {
-        if (isScreenOn()) {
+        if (policyFlags & POLICY_FLAG_INTERACTIVE) {
             policyFlags |= POLICY_FLAG_PASS_TO_USER;
-
-            if (!isScreenBright()) {
-                policyFlags |= POLICY_FLAG_BRIGHT_HERE;
-            }
-        } else {
+        } else if (policyFlags & (POLICY_FLAG_WAKE | POLICY_FLAG_WAKE_DROPPED)) {
             JNIEnv* env = jniEnv();
             jint wmActions = env->CallIntMethod(mServiceObj,
-                        gServiceClassInfo.interceptMotionBeforeQueueingWhenScreenOff,
-                        policyFlags);
+                        gServiceClassInfo.interceptWakeMotionBeforeQueueing,
+                        when, policyFlags);
             if (checkAndClearExceptionFromCallback(env,
-                    "interceptMotionBeforeQueueingWhenScreenOff")) {
+                    "interceptWakeMotionBeforeQueueing")) {
                 wmActions = 0;
             }
 
-            policyFlags |= POLICY_FLAG_WOKE_HERE | POLICY_FLAG_BRIGHT_HERE;
             handleInterceptActions(wmActions, when, /*byref*/ policyFlags);
         }
     } else {
@@ -850,20 +834,6 @@
 
 void NativeInputManager::handleInterceptActions(jint wmActions, nsecs_t when,
         uint32_t& policyFlags) {
-    if (wmActions & WM_ACTION_GO_TO_SLEEP) {
-#if DEBUG_INPUT_DISPATCHER_POLICY
-        ALOGD("handleInterceptActions: Going to sleep.");
-#endif
-        android_server_PowerManagerService_goToSleep(when);
-    }
-
-    if (wmActions & WM_ACTION_WAKE_UP) {
-#if DEBUG_INPUT_DISPATCHER_POLICY
-        ALOGD("handleInterceptActions: Waking up.");
-#endif
-        android_server_PowerManagerService_wakeUp(when);
-    }
-
     if (wmActions & WM_ACTION_PASS_TO_USER) {
         policyFlags |= POLICY_FLAG_PASS_TO_USER;
     } else {
@@ -1143,7 +1113,7 @@
 }
 
 static jint nativeInjectInputEvent(JNIEnv* env, jclass clazz,
-        jlong ptr, jobject inputEventObj, jint injectorPid, jint injectorUid,
+        jlong ptr, jobject inputEventObj, jint displayId, jint injectorPid, jint injectorUid,
         jint syncMode, jint timeoutMillis, jint policyFlags) {
     NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
 
@@ -1156,7 +1126,7 @@
         }
 
         return (jint) im->getInputManager()->getDispatcher()->injectInputEvent(
-                & keyEvent, injectorPid, injectorUid, syncMode, timeoutMillis,
+                & keyEvent, displayId, injectorPid, injectorUid, syncMode, timeoutMillis,
                 uint32_t(policyFlags));
     } else if (env->IsInstanceOf(inputEventObj, gMotionEventClassInfo.clazz)) {
         const MotionEvent* motionEvent = android_view_MotionEvent_getNativePtr(env, inputEventObj);
@@ -1166,7 +1136,7 @@
         }
 
         return (jint) im->getInputManager()->getDispatcher()->injectInputEvent(
-                motionEvent, injectorPid, injectorUid, syncMode, timeoutMillis,
+                motionEvent, displayId, injectorPid, injectorUid, syncMode, timeoutMillis,
                 uint32_t(policyFlags));
     } else {
         jniThrowRuntimeException(env, "Invalid input event type.");
@@ -1237,6 +1207,13 @@
     im->setShowTouches(enabled);
 }
 
+static void nativeSetInteractive(JNIEnv* env,
+        jclass clazz, jlong ptr, jboolean interactive) {
+    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
+
+    im->setInteractive(interactive);
+}
+
 static void nativeVibrate(JNIEnv* env,
         jclass clazz, jlong ptr, jint deviceId, jlongArray patternObj,
         jint repeat, jint token) {
@@ -1326,7 +1303,7 @@
             (void*) nativeUnregisterInputChannel },
     { "nativeSetInputFilterEnabled", "(JZ)V",
             (void*) nativeSetInputFilterEnabled },
-    { "nativeInjectInputEvent", "(JLandroid/view/InputEvent;IIIII)I",
+    { "nativeInjectInputEvent", "(JLandroid/view/InputEvent;IIIIII)I",
             (void*) nativeInjectInputEvent },
     { "nativeSetInputWindows", "(J[Lcom/android/server/input/InputWindowHandle;)V",
             (void*) nativeSetInputWindows },
@@ -1342,6 +1319,8 @@
             (void*) nativeSetPointerSpeed },
     { "nativeSetShowTouches", "(JZ)V",
             (void*) nativeSetShowTouches },
+    { "nativeSetInteractive", "(JZ)V",
+            (void*) nativeSetInteractive },
     { "nativeVibrate", "(JI[JII)V",
             (void*) nativeVibrate },
     { "nativeCancelVibrate", "(JII)V",
@@ -1398,11 +1377,10 @@
             "filterInputEvent", "(Landroid/view/InputEvent;I)Z");
 
     GET_METHOD_ID(gServiceClassInfo.interceptKeyBeforeQueueing, clazz,
-            "interceptKeyBeforeQueueing", "(Landroid/view/KeyEvent;IZ)I");
+            "interceptKeyBeforeQueueing", "(Landroid/view/KeyEvent;I)I");
 
-    GET_METHOD_ID(gServiceClassInfo.interceptMotionBeforeQueueingWhenScreenOff,
-            clazz,
-            "interceptMotionBeforeQueueingWhenScreenOff", "(I)I");
+    GET_METHOD_ID(gServiceClassInfo.interceptWakeMotionBeforeQueueing, clazz,
+            "interceptWakeMotionBeforeQueueing", "(JI)I");
 
     GET_METHOD_ID(gServiceClassInfo.interceptKeyBeforeDispatching, clazz,
             "interceptKeyBeforeDispatching",
@@ -1446,7 +1424,8 @@
             "getPointerIcon", "()Landroid/view/PointerIcon;");
 
     GET_METHOD_ID(gServiceClassInfo.getKeyboardLayoutOverlay, clazz,
-            "getKeyboardLayoutOverlay", "(Ljava/lang/String;)[Ljava/lang/String;");
+            "getKeyboardLayoutOverlay",
+            "(Landroid/hardware/input/InputDeviceIdentifier;)[Ljava/lang/String;");
 
     GET_METHOD_ID(gServiceClassInfo.getDeviceAlias, clazz,
             "getDeviceAlias", "(Ljava/lang/String;)Ljava/lang/String;");
@@ -1466,6 +1445,13 @@
     FIND_CLASS(gMotionEventClassInfo.clazz, "android/view/MotionEvent");
     gMotionEventClassInfo.clazz = jclass(env->NewGlobalRef(gMotionEventClassInfo.clazz));
 
+    // InputDeviceIdentifier
+
+    FIND_CLASS(gInputDeviceIdentifierInfo.clazz, "android/hardware/input/InputDeviceIdentifier");
+    gInputDeviceIdentifierInfo.clazz = jclass(env->NewGlobalRef(gInputDeviceIdentifierInfo.clazz));
+    GET_METHOD_ID(gInputDeviceIdentifierInfo.constructor, gInputDeviceIdentifierInfo.clazz,
+            "<init>", "(Ljava/lang/String;II)V");
+
     return 0;
 }
 
diff --git a/services/jni/com_android_server_input_InputWindowHandle.cpp b/services/core/jni/com_android_server_input_InputWindowHandle.cpp
similarity index 100%
rename from services/jni/com_android_server_input_InputWindowHandle.cpp
rename to services/core/jni/com_android_server_input_InputWindowHandle.cpp
diff --git a/services/jni/com_android_server_input_InputWindowHandle.h b/services/core/jni/com_android_server_input_InputWindowHandle.h
similarity index 100%
rename from services/jni/com_android_server_input_InputWindowHandle.h
rename to services/core/jni/com_android_server_input_InputWindowHandle.h
diff --git a/services/jni/com_android_server_LightsService.cpp b/services/core/jni/com_android_server_lights_LightsService.cpp
similarity index 97%
rename from services/jni/com_android_server_LightsService.cpp
rename to services/core/jni/com_android_server_lights_LightsService.cpp
index 69793f7..d51e044 100644
--- a/services/jni/com_android_server_LightsService.cpp
+++ b/services/core/jni/com_android_server_lights_LightsService.cpp
@@ -134,7 +134,7 @@
 
 int register_android_server_LightsService(JNIEnv *env)
 {
-    return jniRegisterNativeMethods(env, "com/android/server/LightsService",
+    return jniRegisterNativeMethods(env, "com/android/server/lights/LightsService",
             method_table, NELEM(method_table));
 }
 
diff --git a/services/jni/com_android_server_location_FlpHardwareProvider.cpp b/services/core/jni/com_android_server_location_FlpHardwareProvider.cpp
similarity index 100%
rename from services/jni/com_android_server_location_FlpHardwareProvider.cpp
rename to services/core/jni/com_android_server_location_FlpHardwareProvider.cpp
diff --git a/services/jni/com_android_server_location_GpsLocationProvider.cpp b/services/core/jni/com_android_server_location_GpsLocationProvider.cpp
similarity index 100%
rename from services/jni/com_android_server_location_GpsLocationProvider.cpp
rename to services/core/jni/com_android_server_location_GpsLocationProvider.cpp
diff --git a/services/jni/com_android_server_power_PowerManagerService.cpp b/services/core/jni/com_android_server_power_PowerManagerService.cpp
similarity index 79%
rename from services/jni/com_android_server_power_PowerManagerService.cpp
rename to services/core/jni/com_android_server_power_PowerManagerService.cpp
index 151e134..af09861 100644
--- a/services/jni/com_android_server_power_PowerManagerService.cpp
+++ b/services/core/jni/com_android_server_power_PowerManagerService.cpp
@@ -42,8 +42,6 @@
 // ----------------------------------------------------------------------------
 
 static struct {
-    jmethodID wakeUpFromNative;
-    jmethodID goToSleepFromNative;
     jmethodID userActivityFromNative;
 } gPowerManagerServiceClassInfo;
 
@@ -52,10 +50,6 @@
 static jobject gPowerManagerServiceObj;
 static struct power_module* gPowerModule;
 
-static Mutex gPowerManagerLock;
-static bool gScreenOn;
-static bool gScreenBright;
-
 static nsecs_t gLastEventTime[USER_ACTIVITY_EVENT_LAST + 1];
 
 // Throttling interval for user activity calls.
@@ -73,16 +67,6 @@
     return false;
 }
 
-bool android_server_PowerManagerService_isScreenOn() {
-    AutoMutex _l(gPowerManagerLock);
-    return gScreenOn;
-}
-
-bool android_server_PowerManagerService_isScreenBright() {
-    AutoMutex _l(gPowerManagerLock);
-    return gScreenBright;
-}
-
 void android_server_PowerManagerService_userActivity(nsecs_t eventTime, int32_t eventType) {
     // Tell the power HAL when user activity occurs.
     if (gPowerModule && gPowerModule->powerHint) {
@@ -114,28 +98,6 @@
     }
 }
 
-void android_server_PowerManagerService_wakeUp(nsecs_t eventTime) {
-    if (gPowerManagerServiceObj) {
-        JNIEnv* env = AndroidRuntime::getJNIEnv();
-
-        env->CallVoidMethod(gPowerManagerServiceObj,
-                gPowerManagerServiceClassInfo.wakeUpFromNative,
-                nanoseconds_to_milliseconds(eventTime));
-        checkAndClearExceptionFromCallback(env, "wakeUpFromNative");
-    }
-}
-
-void android_server_PowerManagerService_goToSleep(nsecs_t eventTime) {
-    if (gPowerManagerServiceObj) {
-        JNIEnv* env = AndroidRuntime::getJNIEnv();
-
-        env->CallVoidMethod(gPowerManagerServiceObj,
-                gPowerManagerServiceClassInfo.goToSleepFromNative,
-                nanoseconds_to_milliseconds(eventTime), 0);
-        checkAndClearExceptionFromCallback(env, "goToSleepFromNative");
-    }
-}
-
 // ----------------------------------------------------------------------------
 
 static void nativeInit(JNIEnv* env, jobject obj) {
@@ -150,13 +112,6 @@
     }
 }
 
-static void nativeSetPowerState(JNIEnv* env,
-        jclass clazz, jboolean screenOn, jboolean screenBright) {
-    AutoMutex _l(gPowerManagerLock);
-    gScreenOn = screenOn;
-    gScreenBright = screenBright;
-}
-
 static void nativeAcquireSuspendBlocker(JNIEnv *env, jclass clazz, jstring nameStr) {
     ScopedUtfChars name(env, nameStr);
     acquire_wake_lock(PARTIAL_WAKE_LOCK, name.c_str());
@@ -195,8 +150,6 @@
     /* name, signature, funcPtr */
     { "nativeInit", "()V",
             (void*) nativeInit },
-    { "nativeSetPowerState", "(ZZ)V",
-            (void*) nativeSetPowerState },
     { "nativeAcquireSuspendBlocker", "(Ljava/lang/String;)V",
             (void*) nativeAcquireSuspendBlocker },
     { "nativeReleaseSuspendBlocker", "(Ljava/lang/String;)V",
@@ -229,12 +182,6 @@
     jclass clazz;
     FIND_CLASS(clazz, "com/android/server/power/PowerManagerService");
 
-    GET_METHOD_ID(gPowerManagerServiceClassInfo.wakeUpFromNative, clazz,
-            "wakeUpFromNative", "(J)V");
-
-    GET_METHOD_ID(gPowerManagerServiceClassInfo.goToSleepFromNative, clazz,
-            "goToSleepFromNative", "(JI)V");
-
     GET_METHOD_ID(gPowerManagerServiceClassInfo.userActivityFromNative, clazz,
             "userActivityFromNative", "(JII)V");
 
@@ -242,8 +189,6 @@
     for (int i = 0; i <= USER_ACTIVITY_EVENT_LAST; i++) {
         gLastEventTime[i] = LLONG_MIN;
     }
-    gScreenOn = true;
-    gScreenBright = true;
     gPowerManagerServiceObj = NULL;
     gPowerModule = NULL;
     return 0;
diff --git a/services/jni/com_android_server_power_PowerManagerService.h b/services/core/jni/com_android_server_power_PowerManagerService.h
similarity index 78%
rename from services/jni/com_android_server_power_PowerManagerService.h
rename to services/core/jni/com_android_server_power_PowerManagerService.h
index 0808b80..fb8153f 100644
--- a/services/jni/com_android_server_power_PowerManagerService.h
+++ b/services/core/jni/com_android_server_power_PowerManagerService.h
@@ -24,11 +24,7 @@
 
 namespace android {
 
-extern bool android_server_PowerManagerService_isScreenOn();
-extern bool android_server_PowerManagerService_isScreenBright();
 extern void android_server_PowerManagerService_userActivity(nsecs_t eventTime, int32_t eventType);
-extern void android_server_PowerManagerService_wakeUp(nsecs_t eventTime);
-extern void android_server_PowerManagerService_goToSleep(nsecs_t eventTime);
 
 } // namespace android
 
diff --git a/services/jni/onload.cpp b/services/core/jni/onload.cpp
similarity index 92%
rename from services/jni/onload.cpp
rename to services/core/jni/onload.cpp
index efc34a2..904966a 100644
--- a/services/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -21,6 +21,7 @@
 
 namespace android {
 int register_android_server_AlarmManagerService(JNIEnv* env);
+int register_android_server_AssetAtlasService(JNIEnv* env);
 int register_android_server_ConsumerIrService(JNIEnv *env);
 int register_android_server_InputApplicationHandle(JNIEnv* env);
 int register_android_server_InputWindowHandle(JNIEnv* env);
@@ -28,14 +29,15 @@
 int register_android_server_LightsService(JNIEnv* env);
 int register_android_server_PowerManagerService(JNIEnv* env);
 int register_android_server_SerialService(JNIEnv* env);
+int register_android_server_SystemServer(JNIEnv* env);
 int register_android_server_UsbDeviceManager(JNIEnv* env);
 int register_android_server_UsbHostManager(JNIEnv* env);
 int register_android_server_VibratorService(JNIEnv* env);
-int register_android_server_SystemServer(JNIEnv* env);
 int register_android_server_location_GpsLocationProvider(JNIEnv* env);
 int register_android_server_location_FlpHardwareProvider(JNIEnv* env);
 int register_android_server_connectivity_Vpn(JNIEnv* env);
-int register_android_server_AssetAtlasService(JNIEnv* env);
+int register_android_server_dreams_McuHal(JNIEnv* env);
+int register_android_server_hdmi_HdmiCecService(JNIEnv* env);
 };
 
 using namespace android;
@@ -67,7 +69,8 @@
     register_android_server_connectivity_Vpn(env);
     register_android_server_AssetAtlasService(env);
     register_android_server_ConsumerIrService(env);
-
+    register_android_server_dreams_McuHal(env);
+    register_android_server_hdmi_HdmiCecService(env);
 
     return JNI_VERSION_1_4;
 }
diff --git a/services/devicepolicy/Android.mk b/services/devicepolicy/Android.mk
new file mode 100644
index 0000000..a55d138
--- /dev/null
+++ b/services/devicepolicy/Android.mk
@@ -0,0 +1,12 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := services.devicepolicy
+
+LOCAL_SRC_FILES += \
+      $(call all-java-files-under,java)
+
+LOCAL_JAVA_LIBRARIES := conscrypt
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/services/java/com/android/server/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
similarity index 88%
rename from services/java/com/android/server/DevicePolicyManagerService.java
rename to services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 2bb99d6..296d852 100644
--- a/services/java/com/android/server/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server;
+package com.android.server.devicepolicy;
 
 import static android.Manifest.permission.MANAGE_CA_CERTIFICATES;
 
@@ -25,6 +25,7 @@
 import com.android.internal.util.XmlUtils;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.org.conscrypt.TrustedCertificateStore;
+import com.android.server.SystemService;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -117,7 +118,7 @@
  */
 public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
 
-    private static final String TAG = "DevicePolicyManagerService";
+    private static final String LOG_TAG = "DevicePolicyManagerService";
 
     private static final String DEVICE_POLICIES_XML = "device_policies.xml";
 
@@ -149,6 +150,26 @@
      */
     private boolean mHasFeature;
 
+    public static final class Lifecycle extends SystemService {
+        private DevicePolicyManagerService mService;
+
+        public Lifecycle(Context context) {
+            super(context);
+            mService = new DevicePolicyManagerService(context);
+        }
+
+        @Override
+        public void onStart() {
+            publishBinderService(Context.DEVICE_POLICY_SERVICE, mService);
+        }
+
+        @Override
+        public void onBootPhase(int phase) {
+            if (phase == PHASE_LOCK_SETTINGS_READY) {
+                mService.systemReady();
+            }
+        }
+    }
     public static class DevicePolicyData {
         int mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
         int mActivePasswordLength = 0;
@@ -186,7 +207,7 @@
                     getSendingUserId());
             if (Intent.ACTION_BOOT_COMPLETED.equals(action)
                     || ACTION_EXPIRED_PASSWORD_NOTIFICATION.equals(action)) {
-                if (DBG) Slog.v(TAG, "Sending password expiration notifications for action "
+                if (DBG) Slog.v(LOG_TAG, "Sending password expiration notifications for action "
                         + action + " for user " + userHandle);
                 mHandler.post(new Runnable() {
                     public void run() {
@@ -218,6 +239,28 @@
     };
 
     static class ActiveAdmin {
+        private static final String TAG_DISABLE_KEYGUARD_FEATURES = "disable-keyguard-features";
+        private static final String TAG_DISABLE_CAMERA = "disable-camera";
+        private static final String TAG_ENCRYPTION_REQUESTED = "encryption-requested";
+        private static final String TAG_PASSWORD_EXPIRATION_DATE = "password-expiration-date";
+        private static final String TAG_PASSWORD_EXPIRATION_TIMEOUT = "password-expiration-timeout";
+        private static final String TAG_GLOBAL_PROXY_EXCLUSION_LIST = "global-proxy-exclusion-list";
+        private static final String TAG_GLOBAL_PROXY_SPEC = "global-proxy-spec";
+        private static final String TAG_SPECIFIES_GLOBAL_PROXY = "specifies-global-proxy";
+        private static final String TAG_MAX_FAILED_PASSWORD_WIPE = "max-failed-password-wipe";
+        private static final String TAG_MAX_TIME_TO_UNLOCK = "max-time-to-unlock";
+        private static final String TAG_MIN_PASSWORD_NONLETTER = "min-password-nonletter";
+        private static final String TAG_MIN_PASSWORD_SYMBOLS = "min-password-symbols";
+        private static final String TAG_MIN_PASSWORD_NUMERIC = "min-password-numeric";
+        private static final String TAG_MIN_PASSWORD_LETTERS = "min-password-letters";
+        private static final String TAG_MIN_PASSWORD_LOWERCASE = "min-password-lowercase";
+        private static final String TAG_MIN_PASSWORD_UPPERCASE = "min-password-uppercase";
+        private static final String TAG_PASSWORD_HISTORY_LENGTH = "password-history-length";
+        private static final String TAG_MIN_PASSWORD_LENGTH = "min-password-length";
+        private static final String ATTR_VALUE = "value";
+        private static final String TAG_PASSWORD_QUALITY = "password-quality";
+        private static final String TAG_POLICIES = "policies";
+
         final DeviceAdminInfo info;
 
         int passwordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
@@ -281,103 +324,103 @@
 
         void writeToXml(XmlSerializer out)
                 throws IllegalArgumentException, IllegalStateException, IOException {
-            out.startTag(null, "policies");
+            out.startTag(null, TAG_POLICIES);
             info.writePoliciesToXml(out);
-            out.endTag(null, "policies");
+            out.endTag(null, TAG_POLICIES);
             if (passwordQuality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
-                out.startTag(null, "password-quality");
-                out.attribute(null, "value", Integer.toString(passwordQuality));
-                out.endTag(null, "password-quality");
+                out.startTag(null, TAG_PASSWORD_QUALITY);
+                out.attribute(null, ATTR_VALUE, Integer.toString(passwordQuality));
+                out.endTag(null, TAG_PASSWORD_QUALITY);
                 if (minimumPasswordLength != DEF_MINIMUM_PASSWORD_LENGTH) {
-                    out.startTag(null, "min-password-length");
-                    out.attribute(null, "value", Integer.toString(minimumPasswordLength));
-                    out.endTag(null, "min-password-length");
+                    out.startTag(null, TAG_MIN_PASSWORD_LENGTH);
+                    out.attribute(null, ATTR_VALUE, Integer.toString(minimumPasswordLength));
+                    out.endTag(null, TAG_MIN_PASSWORD_LENGTH);
                 }
                 if(passwordHistoryLength != DEF_PASSWORD_HISTORY_LENGTH) {
-                    out.startTag(null, "password-history-length");
-                    out.attribute(null, "value", Integer.toString(passwordHistoryLength));
-                    out.endTag(null, "password-history-length");
+                    out.startTag(null, TAG_PASSWORD_HISTORY_LENGTH);
+                    out.attribute(null, ATTR_VALUE, Integer.toString(passwordHistoryLength));
+                    out.endTag(null, TAG_PASSWORD_HISTORY_LENGTH);
                 }
                 if (minimumPasswordUpperCase != DEF_MINIMUM_PASSWORD_UPPER_CASE) {
-                    out.startTag(null, "min-password-uppercase");
-                    out.attribute(null, "value", Integer.toString(minimumPasswordUpperCase));
-                    out.endTag(null, "min-password-uppercase");
+                    out.startTag(null, TAG_MIN_PASSWORD_UPPERCASE);
+                    out.attribute(null, ATTR_VALUE, Integer.toString(minimumPasswordUpperCase));
+                    out.endTag(null, TAG_MIN_PASSWORD_UPPERCASE);
                 }
                 if (minimumPasswordLowerCase != DEF_MINIMUM_PASSWORD_LOWER_CASE) {
-                    out.startTag(null, "min-password-lowercase");
-                    out.attribute(null, "value", Integer.toString(minimumPasswordLowerCase));
-                    out.endTag(null, "min-password-lowercase");
+                    out.startTag(null, TAG_MIN_PASSWORD_LOWERCASE);
+                    out.attribute(null, ATTR_VALUE, Integer.toString(minimumPasswordLowerCase));
+                    out.endTag(null, TAG_MIN_PASSWORD_LOWERCASE);
                 }
                 if (minimumPasswordLetters != DEF_MINIMUM_PASSWORD_LETTERS) {
-                    out.startTag(null, "min-password-letters");
-                    out.attribute(null, "value", Integer.toString(minimumPasswordLetters));
-                    out.endTag(null, "min-password-letters");
+                    out.startTag(null, TAG_MIN_PASSWORD_LETTERS);
+                    out.attribute(null, ATTR_VALUE, Integer.toString(minimumPasswordLetters));
+                    out.endTag(null, TAG_MIN_PASSWORD_LETTERS);
                 }
                 if (minimumPasswordNumeric != DEF_MINIMUM_PASSWORD_NUMERIC) {
-                    out.startTag(null, "min-password-numeric");
-                    out.attribute(null, "value", Integer.toString(minimumPasswordNumeric));
-                    out.endTag(null, "min-password-numeric");
+                    out.startTag(null, TAG_MIN_PASSWORD_NUMERIC);
+                    out.attribute(null, ATTR_VALUE, Integer.toString(minimumPasswordNumeric));
+                    out.endTag(null, TAG_MIN_PASSWORD_NUMERIC);
                 }
                 if (minimumPasswordSymbols != DEF_MINIMUM_PASSWORD_SYMBOLS) {
-                    out.startTag(null, "min-password-symbols");
-                    out.attribute(null, "value", Integer.toString(minimumPasswordSymbols));
-                    out.endTag(null, "min-password-symbols");
+                    out.startTag(null, TAG_MIN_PASSWORD_SYMBOLS);
+                    out.attribute(null, ATTR_VALUE, Integer.toString(minimumPasswordSymbols));
+                    out.endTag(null, TAG_MIN_PASSWORD_SYMBOLS);
                 }
                 if (minimumPasswordNonLetter > DEF_MINIMUM_PASSWORD_NON_LETTER) {
-                    out.startTag(null, "min-password-nonletter");
-                    out.attribute(null, "value", Integer.toString(minimumPasswordNonLetter));
-                    out.endTag(null, "min-password-nonletter");
+                    out.startTag(null, TAG_MIN_PASSWORD_NONLETTER);
+                    out.attribute(null, ATTR_VALUE, Integer.toString(minimumPasswordNonLetter));
+                    out.endTag(null, TAG_MIN_PASSWORD_NONLETTER);
                 }
             }
             if (maximumTimeToUnlock != DEF_MAXIMUM_TIME_TO_UNLOCK) {
-                out.startTag(null, "max-time-to-unlock");
-                out.attribute(null, "value", Long.toString(maximumTimeToUnlock));
-                out.endTag(null, "max-time-to-unlock");
+                out.startTag(null, TAG_MAX_TIME_TO_UNLOCK);
+                out.attribute(null, ATTR_VALUE, Long.toString(maximumTimeToUnlock));
+                out.endTag(null, TAG_MAX_TIME_TO_UNLOCK);
             }
             if (maximumFailedPasswordsForWipe != DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE) {
-                out.startTag(null, "max-failed-password-wipe");
-                out.attribute(null, "value", Integer.toString(maximumFailedPasswordsForWipe));
-                out.endTag(null, "max-failed-password-wipe");
+                out.startTag(null, TAG_MAX_FAILED_PASSWORD_WIPE);
+                out.attribute(null, ATTR_VALUE, Integer.toString(maximumFailedPasswordsForWipe));
+                out.endTag(null, TAG_MAX_FAILED_PASSWORD_WIPE);
             }
             if (specifiesGlobalProxy) {
-                out.startTag(null, "specifies-global-proxy");
-                out.attribute(null, "value", Boolean.toString(specifiesGlobalProxy));
-                out.endTag(null, "specifies_global_proxy");
+                out.startTag(null, TAG_SPECIFIES_GLOBAL_PROXY);
+                out.attribute(null, ATTR_VALUE, Boolean.toString(specifiesGlobalProxy));
+                out.endTag(null, TAG_SPECIFIES_GLOBAL_PROXY);
                 if (globalProxySpec != null) {
-                    out.startTag(null, "global-proxy-spec");
-                    out.attribute(null, "value", globalProxySpec);
-                    out.endTag(null, "global-proxy-spec");
+                    out.startTag(null, TAG_GLOBAL_PROXY_SPEC);
+                    out.attribute(null, ATTR_VALUE, globalProxySpec);
+                    out.endTag(null, TAG_GLOBAL_PROXY_SPEC);
                 }
                 if (globalProxyExclusionList != null) {
-                    out.startTag(null, "global-proxy-exclusion-list");
-                    out.attribute(null, "value", globalProxyExclusionList);
-                    out.endTag(null, "global-proxy-exclusion-list");
+                    out.startTag(null, TAG_GLOBAL_PROXY_EXCLUSION_LIST);
+                    out.attribute(null, ATTR_VALUE, globalProxyExclusionList);
+                    out.endTag(null, TAG_GLOBAL_PROXY_EXCLUSION_LIST);
                 }
             }
             if (passwordExpirationTimeout != DEF_PASSWORD_EXPIRATION_TIMEOUT) {
-                out.startTag(null, "password-expiration-timeout");
-                out.attribute(null, "value", Long.toString(passwordExpirationTimeout));
-                out.endTag(null, "password-expiration-timeout");
+                out.startTag(null, TAG_PASSWORD_EXPIRATION_TIMEOUT);
+                out.attribute(null, ATTR_VALUE, Long.toString(passwordExpirationTimeout));
+                out.endTag(null, TAG_PASSWORD_EXPIRATION_TIMEOUT);
             }
             if (passwordExpirationDate != DEF_PASSWORD_EXPIRATION_DATE) {
-                out.startTag(null, "password-expiration-date");
-                out.attribute(null, "value", Long.toString(passwordExpirationDate));
-                out.endTag(null, "password-expiration-date");
+                out.startTag(null, TAG_PASSWORD_EXPIRATION_DATE);
+                out.attribute(null, ATTR_VALUE, Long.toString(passwordExpirationDate));
+                out.endTag(null, TAG_PASSWORD_EXPIRATION_DATE);
             }
             if (encryptionRequested) {
-                out.startTag(null, "encryption-requested");
-                out.attribute(null, "value", Boolean.toString(encryptionRequested));
-                out.endTag(null, "encryption-requested");
+                out.startTag(null, TAG_ENCRYPTION_REQUESTED);
+                out.attribute(null, ATTR_VALUE, Boolean.toString(encryptionRequested));
+                out.endTag(null, TAG_ENCRYPTION_REQUESTED);
             }
             if (disableCamera) {
-                out.startTag(null, "disable-camera");
-                out.attribute(null, "value", Boolean.toString(disableCamera));
-                out.endTag(null, "disable-camera");
+                out.startTag(null, TAG_DISABLE_CAMERA);
+                out.attribute(null, ATTR_VALUE, Boolean.toString(disableCamera));
+                out.endTag(null, TAG_DISABLE_CAMERA);
             }
             if (disabledKeyguardFeatures != DEF_KEYGUARD_FEATURES_DISABLED) {
-                out.startTag(null, "disable-keyguard-features");
-                out.attribute(null, "value", Integer.toString(disabledKeyguardFeatures));
-                out.endTag(null, "disable-keyguard-features");
+                out.startTag(null, TAG_DISABLE_KEYGUARD_FEATURES);
+                out.attribute(null, ATTR_VALUE, Integer.toString(disabledKeyguardFeatures));
+                out.endTag(null, TAG_DISABLE_KEYGUARD_FEATURES);
             }
         }
 
@@ -391,67 +434,67 @@
                     continue;
                 }
                 String tag = parser.getName();
-                if ("policies".equals(tag)) {
+                if (TAG_POLICIES.equals(tag)) {
                     info.readPoliciesFromXml(parser);
-                } else if ("password-quality".equals(tag)) {
+                } else if (TAG_PASSWORD_QUALITY.equals(tag)) {
                     passwordQuality = Integer.parseInt(
-                            parser.getAttributeValue(null, "value"));
-                } else if ("min-password-length".equals(tag)) {
+                            parser.getAttributeValue(null, ATTR_VALUE));
+                } else if (TAG_MIN_PASSWORD_LENGTH.equals(tag)) {
                     minimumPasswordLength = Integer.parseInt(
-                            parser.getAttributeValue(null, "value"));
-                } else if ("password-history-length".equals(tag)) {
+                            parser.getAttributeValue(null, ATTR_VALUE));
+                } else if (TAG_PASSWORD_HISTORY_LENGTH.equals(tag)) {
                     passwordHistoryLength = Integer.parseInt(
-                            parser.getAttributeValue(null, "value"));
-                } else if ("min-password-uppercase".equals(tag)) {
+                            parser.getAttributeValue(null, ATTR_VALUE));
+                } else if (TAG_MIN_PASSWORD_UPPERCASE.equals(tag)) {
                     minimumPasswordUpperCase = Integer.parseInt(
-                            parser.getAttributeValue(null, "value"));
-                } else if ("min-password-lowercase".equals(tag)) {
+                            parser.getAttributeValue(null, ATTR_VALUE));
+                } else if (TAG_MIN_PASSWORD_LOWERCASE.equals(tag)) {
                     minimumPasswordLowerCase = Integer.parseInt(
-                            parser.getAttributeValue(null, "value"));
-                } else if ("min-password-letters".equals(tag)) {
+                            parser.getAttributeValue(null, ATTR_VALUE));
+                } else if (TAG_MIN_PASSWORD_LETTERS.equals(tag)) {
                     minimumPasswordLetters = Integer.parseInt(
-                            parser.getAttributeValue(null, "value"));
-                } else if ("min-password-numeric".equals(tag)) {
+                            parser.getAttributeValue(null, ATTR_VALUE));
+                } else if (TAG_MIN_PASSWORD_NUMERIC.equals(tag)) {
                     minimumPasswordNumeric = Integer.parseInt(
-                            parser.getAttributeValue(null, "value"));
-                } else if ("min-password-symbols".equals(tag)) {
+                            parser.getAttributeValue(null, ATTR_VALUE));
+                } else if (TAG_MIN_PASSWORD_SYMBOLS.equals(tag)) {
                     minimumPasswordSymbols = Integer.parseInt(
-                            parser.getAttributeValue(null, "value"));
-                } else if ("min-password-nonletter".equals(tag)) {
+                            parser.getAttributeValue(null, ATTR_VALUE));
+                } else if (TAG_MIN_PASSWORD_NONLETTER.equals(tag)) {
                     minimumPasswordNonLetter = Integer.parseInt(
-                            parser.getAttributeValue(null, "value"));
-                } else if ("max-time-to-unlock".equals(tag)) {
+                            parser.getAttributeValue(null, ATTR_VALUE));
+                } else if (TAG_MAX_TIME_TO_UNLOCK.equals(tag)) {
                     maximumTimeToUnlock = Long.parseLong(
-                            parser.getAttributeValue(null, "value"));
-                } else if ("max-failed-password-wipe".equals(tag)) {
+                            parser.getAttributeValue(null, ATTR_VALUE));
+                } else if (TAG_MAX_FAILED_PASSWORD_WIPE.equals(tag)) {
                     maximumFailedPasswordsForWipe = Integer.parseInt(
-                            parser.getAttributeValue(null, "value"));
-                } else if ("specifies-global-proxy".equals(tag)) {
+                            parser.getAttributeValue(null, ATTR_VALUE));
+                } else if (TAG_SPECIFIES_GLOBAL_PROXY.equals(tag)) {
                     specifiesGlobalProxy = Boolean.parseBoolean(
-                            parser.getAttributeValue(null, "value"));
-                } else if ("global-proxy-spec".equals(tag)) {
+                            parser.getAttributeValue(null, ATTR_VALUE));
+                } else if (TAG_GLOBAL_PROXY_SPEC.equals(tag)) {
                     globalProxySpec =
-                        parser.getAttributeValue(null, "value");
-                } else if ("global-proxy-exclusion-list".equals(tag)) {
+                        parser.getAttributeValue(null, ATTR_VALUE);
+                } else if (TAG_GLOBAL_PROXY_EXCLUSION_LIST.equals(tag)) {
                     globalProxyExclusionList =
-                        parser.getAttributeValue(null, "value");
-                } else if ("password-expiration-timeout".equals(tag)) {
+                        parser.getAttributeValue(null, ATTR_VALUE);
+                } else if (TAG_PASSWORD_EXPIRATION_TIMEOUT.equals(tag)) {
                     passwordExpirationTimeout = Long.parseLong(
-                            parser.getAttributeValue(null, "value"));
-                } else if ("password-expiration-date".equals(tag)) {
+                            parser.getAttributeValue(null, ATTR_VALUE));
+                } else if (TAG_PASSWORD_EXPIRATION_DATE.equals(tag)) {
                     passwordExpirationDate = Long.parseLong(
-                            parser.getAttributeValue(null, "value"));
-                } else if ("encryption-requested".equals(tag)) {
+                            parser.getAttributeValue(null, ATTR_VALUE));
+                } else if (TAG_ENCRYPTION_REQUESTED.equals(tag)) {
                     encryptionRequested = Boolean.parseBoolean(
-                            parser.getAttributeValue(null, "value"));
-                } else if ("disable-camera".equals(tag)) {
+                            parser.getAttributeValue(null, ATTR_VALUE));
+                } else if (TAG_DISABLE_CAMERA.equals(tag)) {
                     disableCamera = Boolean.parseBoolean(
-                            parser.getAttributeValue(null, "value"));
-                } else if ("disable-keyguard-features".equals(tag)) {
+                            parser.getAttributeValue(null, ATTR_VALUE));
+                } else if (TAG_DISABLE_KEYGUARD_FEATURES.equals(tag)) {
                     disabledKeyguardFeatures = Integer.parseInt(
-                            parser.getAttributeValue(null, "value"));
+                            parser.getAttributeValue(null, ATTR_VALUE));
                 } else {
-                    Slog.w(TAG, "Unknown admin tag: " + tag);
+                    Slog.w(LOG_TAG, "Unknown admin tag: " + tag);
                 }
                 XmlUtils.skipCurrentTag(parser);
             }
@@ -513,7 +556,7 @@
 
     private void handlePackagesChanged(int userHandle) {
         boolean removed = false;
-        if (DBG) Slog.d(TAG, "Handling package changes for user " + userHandle);
+        if (DBG) Slog.d(LOG_TAG, "Handling package changes for user " + userHandle);
         DevicePolicyData policy = getUserData(userHandle);
         IPackageManager pm = AppGlobals.getPackageManager();
         for (int i = policy.mAdminList.size() - 1; i >= 0; i--) {
@@ -585,7 +628,7 @@
     void removeUserData(int userHandle) {
         synchronized (this) {
             if (userHandle == UserHandle.USER_OWNER) {
-                Slog.w(TAG, "Tried to remove device policy file for user 0! Ignoring.");
+                Slog.w(LOG_TAG, "Tried to remove device policy file for user 0! Ignoring.");
                 return;
             }
             DevicePolicyData policy = mUserData.get(userHandle);
@@ -595,7 +638,7 @@
             File policyFile = new File(Environment.getUserSystemDirectory(userHandle),
                     DEVICE_POLICIES_XML);
             policyFile.delete();
-            Slog.i(TAG, "Removed device policy file " + policyFile.getAbsolutePath());
+            Slog.i(LOG_TAG, "Removed device policy file " + policyFile.getAbsolutePath());
         }
     }
 
@@ -792,10 +835,12 @@
         try {
             return new DeviceAdminInfo(mContext, infos.get(0));
         } catch (XmlPullParserException e) {
-            Slog.w(TAG, "Bad device admin requested for user=" + userHandle + ": " + adminName, e);
+            Slog.w(LOG_TAG, "Bad device admin requested for user=" + userHandle + ": " + adminName,
+                    e);
             return null;
         } catch (IOException e) {
-            Slog.w(TAG, "Bad device admin requested for user=" + userHandle + ": " + adminName, e);
+            Slog.w(LOG_TAG, "Bad device admin requested for user=" + userHandle + ": " + adminName,
+                    e);
             return null;
         }
     }
@@ -922,7 +967,7 @@
                                 ComponentName.unflattenFromString(name), userHandle);
                         if (DBG && (UserHandle.getUserId(dai.getActivityInfo().applicationInfo.uid)
                                 != userHandle)) {
-                            Slog.w(TAG, "findAdmin returned an incorrect uid "
+                            Slog.w(LOG_TAG, "findAdmin returned an incorrect uid "
                                     + dai.getActivityInfo().applicationInfo.uid + " for user "
                                     + userHandle);
                         }
@@ -933,7 +978,7 @@
                             policy.mAdminList.add(ap);
                         }
                     } catch (RuntimeException e) {
-                        Slog.w(TAG, "Failed loading admin " + name, e);
+                        Slog.w(LOG_TAG, "Failed loading admin " + name, e);
                     }
                 } else if ("failed-password-attempts".equals(tag)) {
                     policy.mFailedPasswordAttempts = Integer.parseInt(
@@ -962,22 +1007,22 @@
                             parser.getAttributeValue(null, "nonletter"));
                     XmlUtils.skipCurrentTag(parser);
                 } else {
-                    Slog.w(TAG, "Unknown tag: " + tag);
+                    Slog.w(LOG_TAG, "Unknown tag: " + tag);
                     XmlUtils.skipCurrentTag(parser);
                 }
             }
         } catch (NullPointerException e) {
-            Slog.w(TAG, "failed parsing " + file + " " + e);
+            Slog.w(LOG_TAG, "failed parsing " + file + " " + e);
         } catch (NumberFormatException e) {
-            Slog.w(TAG, "failed parsing " + file + " " + e);
+            Slog.w(LOG_TAG, "failed parsing " + file + " " + e);
         } catch (XmlPullParserException e) {
-            Slog.w(TAG, "failed parsing " + file + " " + e);
+            Slog.w(LOG_TAG, "failed parsing " + file + " " + e);
         } catch (FileNotFoundException e) {
             // Don't be noisy, this is normal if we haven't defined any policies.
         } catch (IOException e) {
-            Slog.w(TAG, "failed parsing " + file + " " + e);
+            Slog.w(LOG_TAG, "failed parsing " + file + " " + e);
         } catch (IndexOutOfBoundsException e) {
-            Slog.w(TAG, "failed parsing " + file + " " + e);
+            Slog.w(LOG_TAG, "failed parsing " + file + " " + e);
         }
         try {
             if (stream != null) {
@@ -993,7 +1038,7 @@
         // never normally happen.
         LockPatternUtils utils = new LockPatternUtils(mContext);
         if (utils.getActivePasswordQuality() < policy.mActivePasswordQuality) {
-            Slog.w(TAG, "Active password quality 0x"
+            Slog.w(LOG_TAG, "Active password quality 0x"
                     + Integer.toHexString(policy.mActivePasswordQuality)
                     + " does not match actual quality 0x"
                     + Integer.toHexString(utils.getActivePasswordQuality()));
@@ -1037,7 +1082,7 @@
                 }
             }
             if (!haveOwner) {
-                Slog.w(TAG, "Previous password owner " + policy.mPasswordOwner
+                Slog.w(LOG_TAG, "Previous password owner " + policy.mPasswordOwner
                         + " no longer active; disabling");
                 policy.mPasswordOwner = -1;
             }
@@ -1057,7 +1102,7 @@
             long token = Binder.clearCallingIdentity();
             try {
                 String value = cameraDisabled ? "1" : "0";
-                if (DBG) Slog.v(TAG, "Change in camera state ["
+                if (DBG) Slog.v(LOG_TAG, "Change in camera state ["
                         + SYSTEM_PROP_DISABLE_CAMERA + "] = " + value);
                 SystemProperties.set(SYSTEM_PROP_DISABLE_CAMERA, value);
             } finally {
@@ -1173,7 +1218,8 @@
         synchronized (this) {
             long ident = Binder.clearCallingIdentity();
             try {
-                if (!refreshing && getActiveAdminUncheckedLocked(adminReceiver, userHandle) != null) {
+                if (!refreshing
+                        && getActiveAdminUncheckedLocked(adminReceiver, userHandle) != null) {
                     throw new IllegalArgumentException("Admin is already added");
                 }
                 ActiveAdmin newAdmin = new ActiveAdmin(info);
@@ -1443,7 +1489,7 @@
             ap.passwordExpirationDate = expiration;
             ap.passwordExpirationTimeout = timeout;
             if (timeout > 0L) {
-                Slog.w(TAG, "setPasswordExpiration(): password will expire on "
+                Slog.w(LOG_TAG, "setPasswordExpiration(): password will expire on "
                         + DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT)
                         .format(new Date(expiration)));
             }
@@ -1789,11 +1835,11 @@
                 return true;
             }
             return policy.mActivePasswordUpperCase >= getPasswordMinimumUpperCase(null, userHandle)
-                    && policy.mActivePasswordLowerCase >= getPasswordMinimumLowerCase(null, userHandle)
-                    && policy.mActivePasswordLetters >= getPasswordMinimumLetters(null, userHandle)
-                    && policy.mActivePasswordNumeric >= getPasswordMinimumNumeric(null, userHandle)
-                    && policy.mActivePasswordSymbols >= getPasswordMinimumSymbols(null, userHandle)
-                    && policy.mActivePasswordNonLetter >= getPasswordMinimumNonLetter(null, userHandle);
+                && policy.mActivePasswordLowerCase >= getPasswordMinimumLowerCase(null, userHandle)
+                && policy.mActivePasswordLetters >= getPasswordMinimumLetters(null, userHandle)
+                && policy.mActivePasswordNumeric >= getPasswordMinimumNumeric(null, userHandle)
+                && policy.mActivePasswordSymbols >= getPasswordMinimumSymbols(null, userHandle)
+                && policy.mActivePasswordNonLetter >= getPasswordMinimumNonLetter(null, userHandle);
         }
     }
 
@@ -1871,7 +1917,7 @@
                 int realQuality = LockPatternUtils.computePasswordQuality(password);
                 if (realQuality < quality
                         && quality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
-                    Slog.w(TAG, "resetPassword: password quality 0x"
+                    Slog.w(LOG_TAG, "resetPassword: password quality 0x"
                             + Integer.toHexString(realQuality)
                             + " does not meet required quality 0x"
                             + Integer.toHexString(quality));
@@ -1881,7 +1927,7 @@
             }
             int length = getPasswordMinimumLength(null, userHandle);
             if (password.length() < length) {
-                Slog.w(TAG, "resetPassword: password length " + password.length()
+                Slog.w(LOG_TAG, "resetPassword: password length " + password.length()
                         + " does not meet required length " + length);
                 return false;
             }
@@ -1910,40 +1956,40 @@
                 }
                 int neededLetters = getPasswordMinimumLetters(null, userHandle);
                 if(letters < neededLetters) {
-                    Slog.w(TAG, "resetPassword: number of letters " + letters
+                    Slog.w(LOG_TAG, "resetPassword: number of letters " + letters
                             + " does not meet required number of letters " + neededLetters);
                     return false;
                 }
                 int neededNumbers = getPasswordMinimumNumeric(null, userHandle);
                 if (numbers < neededNumbers) {
-                    Slog.w(TAG, "resetPassword: number of numerical digits " + numbers
+                    Slog.w(LOG_TAG, "resetPassword: number of numerical digits " + numbers
                             + " does not meet required number of numerical digits "
                             + neededNumbers);
                     return false;
                 }
                 int neededLowerCase = getPasswordMinimumLowerCase(null, userHandle);
                 if (lowercase < neededLowerCase) {
-                    Slog.w(TAG, "resetPassword: number of lowercase letters " + lowercase
+                    Slog.w(LOG_TAG, "resetPassword: number of lowercase letters " + lowercase
                             + " does not meet required number of lowercase letters "
                             + neededLowerCase);
                     return false;
                 }
                 int neededUpperCase = getPasswordMinimumUpperCase(null, userHandle);
                 if (uppercase < neededUpperCase) {
-                    Slog.w(TAG, "resetPassword: number of uppercase letters " + uppercase
+                    Slog.w(LOG_TAG, "resetPassword: number of uppercase letters " + uppercase
                             + " does not meet required number of uppercase letters "
                             + neededUpperCase);
                     return false;
                 }
                 int neededSymbols = getPasswordMinimumSymbols(null, userHandle);
                 if (symbols < neededSymbols) {
-                    Slog.w(TAG, "resetPassword: number of special symbols " + symbols
+                    Slog.w(LOG_TAG, "resetPassword: number of special symbols " + symbols
                             + " does not meet required number of special symbols " + neededSymbols);
                     return false;
                 }
                 int neededNonLetter = getPasswordMinimumNonLetter(null, userHandle);
                 if (nonletter < neededNonLetter) {
-                    Slog.w(TAG, "resetPassword: number of non-letter characters " + nonletter
+                    Slog.w(LOG_TAG, "resetPassword: number of non-letter characters " + nonletter
                             + " does not meet required number of non-letter characters "
                             + neededNonLetter);
                     return false;
@@ -1954,7 +2000,7 @@
         int callingUid = Binder.getCallingUid();
         DevicePolicyData policy = getUserData(userHandle);
         if (policy.mPasswordOwner >= 0 && policy.mPasswordOwner != callingUid) {
-            Slog.w(TAG, "resetPassword: already set by another uid and not entered by user");
+            Slog.w(LOG_TAG, "resetPassword: already set by another uid and not entered by user");
             return false;
         }
 
@@ -2020,7 +2066,7 @@
             try {
                 getIPowerManager().setMaximumScreenOffTimeoutFromDeviceAdmin((int)timeMs);
             } catch (RemoteException e) {
-                Slog.w(TAG, "Failure talking with power manager", e);
+                Slog.w(LOG_TAG, "Failure talking with power manager", e);
             }
         } finally {
             Binder.restoreCallingIdentity(ident);
@@ -2095,10 +2141,10 @@
             X509Certificate cert = parseCert(certBuffer);
             pemCert =  Credentials.convertToPem(cert);
         } catch (CertificateException ce) {
-            Log.e(TAG, "Problem converting cert", ce);
+            Log.e(LOG_TAG, "Problem converting cert", ce);
             return false;
         } catch (IOException ioe) {
-            Log.e(TAG, "Problem reading cert", ioe);
+            Log.e(LOG_TAG, "Problem reading cert", ioe);
             return false;
         }
         try {
@@ -2113,7 +2159,7 @@
                 }
             }
         } catch (InterruptedException e1) {
-            Log.w(TAG, "installCaCertsToKeyChain(): ", e1);
+            Log.w(LOG_TAG, "installCaCertsToKeyChain(): ", e1);
             Thread.currentThread().interrupt();
         }
         return false;
@@ -2134,10 +2180,10 @@
             X509Certificate cert = parseCert(certBuffer);
             alias = certStore.getCertificateAlias(cert);
         } catch (CertificateException ce) {
-            Log.e(TAG, "Problem creating X509Certificate", ce);
+            Log.e(LOG_TAG, "Problem creating X509Certificate", ce);
             return;
         } catch (IOException ioe) {
-            Log.e(TAG, "Problem reading certificate", ioe);
+            Log.e(LOG_TAG, "Problem reading certificate", ioe);
             return;
         }
         try {
@@ -2146,13 +2192,13 @@
             try {
                 service.deleteCaCertificate(alias);
             } catch (RemoteException e) {
-                Log.e(TAG, "from CaCertUninstaller: ", e);
+                Log.e(LOG_TAG, "from CaCertUninstaller: ", e);
             } finally {
                 keyChainConnection.close();
                 keyChainConnection = null;
             }
         } catch (InterruptedException ie) {
-            Log.w(TAG, "CaCertUninstaller: ", ie);
+            Log.w(LOG_TAG, "CaCertUninstaller: ", ie);
             Thread.currentThread().interrupt();
         }
     }
@@ -2173,7 +2219,7 @@
             try {
                 RecoverySystem.rebootWipeUserData(mContext);
             } catch (IOException e) {
-                Slog.w(TAG, "Failed requesting data wipe", e);
+                Slog.w(LOG_TAG, "Failed requesting data wipe", e);
             }
         }
     }
@@ -2264,8 +2310,10 @@
             if (p.mActivePasswordQuality != quality || p.mActivePasswordLength != length
                     || p.mFailedPasswordAttempts != 0 || p.mActivePasswordLetters != letters
                     || p.mActivePasswordUpperCase != uppercase
-                    || p.mActivePasswordLowerCase != lowercase || p.mActivePasswordNumeric != numbers
-                    || p.mActivePasswordSymbols != symbols || p.mActivePasswordNonLetter != nonletter) {
+                    || p.mActivePasswordLowerCase != lowercase
+                    || p.mActivePasswordNumeric != numbers
+                    || p.mActivePasswordSymbols != symbols
+                    || p.mActivePasswordNonLetter != nonletter) {
                 long ident = Binder.clearCallingIdentity();
                 try {
                     p.mActivePasswordQuality = quality;
@@ -2387,7 +2435,7 @@
 
             // If the user is not the owner, don't set the global proxy. Fail silently.
             if (UserHandle.getCallingUserId() != UserHandle.USER_OWNER) {
-                Slog.w(TAG, "Only the owner is allowed to set the global proxy. User "
+                Slog.w(LOG_TAG, "Only the owner is allowed to set the global proxy. User "
                         + userHandle + " is not permitted.");
                 return null;
             }
@@ -2468,7 +2516,7 @@
 
         ProxyProperties proxyProperties = new ProxyProperties(data[0], proxyPort, exclusionList);
         if (!proxyProperties.isValid()) {
-            Slog.e(TAG, "Invalid proxy properties, ignoring: " + proxyProperties.toString());
+            Slog.e(LOG_TAG, "Invalid proxy properties, ignoring: " + proxyProperties.toString());
             return;
         }
         Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_HOST, data[0]);
@@ -2494,7 +2542,7 @@
             // Only owner can set storage encryption
             if (userHandle != UserHandle.USER_OWNER
                     || UserHandle.getCallingUserId() != UserHandle.USER_OWNER) {
-                Slog.w(TAG, "Only owner is allowed to set storage encryption. User "
+                Slog.w(LOG_TAG, "Only owner is allowed to set storage encryption. User "
                         + UserHandle.getCallingUserId() + " is not permitted.");
                 return 0;
             }
@@ -2880,7 +2928,7 @@
                     }
                 }
             } catch (NameNotFoundException nnfe) {
-                Slog.w(TAG, "Device Owner package " + packageName + " not installed.");
+                Slog.w(LOG_TAG, "Device Owner package " + packageName + " not installed.");
             }
             return false;
         }
@@ -2905,9 +2953,9 @@
                 mOwnerName = parser.getAttributeValue(null, ATTR_NAME);
                 input.close();
             } catch (XmlPullParserException xppe) {
-                Slog.e(TAG, "Error parsing device-owner file\n" + xppe);
+                Slog.e(LOG_TAG, "Error parsing device-owner file\n" + xppe);
             } catch (IOException ioe) {
-                Slog.e(TAG, "IO Exception when reading device-owner file\n" + ioe);
+                Slog.e(LOG_TAG, "IO Exception when reading device-owner file\n" + ioe);
             }
         }
 
@@ -2935,7 +2983,7 @@
                 out.flush();
                 file.finishWrite(output);
             } catch (IOException ioe) {
-                Slog.e(TAG, "IO Exception when writing device-owner file\n" + ioe);
+                Slog.e(LOG_TAG, "IO Exception when writing device-owner file\n" + ioe);
             }
         }
     }
diff --git a/services/java/Android.mk b/services/java/Android.mk
deleted file mode 100644
index 8c3d0f0..0000000
--- a/services/java/Android.mk
+++ /dev/null
@@ -1,18 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-# the library
-# ============================================================
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
-            $(call all-subdir-java-files) \
-	    com/android/server/EventLogTags.logtags \
-	    com/android/server/am/EventLogTags.logtags
-
-LOCAL_MODULE:= services
-
-LOCAL_JAVA_LIBRARIES := android.policy conscrypt telephony-common
-
-include $(BUILD_JAVA_LIBRARY)
-
-include $(BUILD_DROIDDOC)
diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java
deleted file mode 100644
index 203cca6..0000000
--- a/services/java/com/android/server/AppWidgetService.java
+++ /dev/null
@@ -1,363 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR 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;
-
-import android.app.ActivityManager;
-import android.appwidget.AppWidgetProviderInfo;
-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.os.Binder;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.util.Slog;
-import android.util.SparseArray;
-import android.widget.RemoteViews;
-
-import com.android.internal.appwidget.IAppWidgetHost;
-import com.android.internal.appwidget.IAppWidgetService;
-import com.android.internal.os.BackgroundThread;
-import com.android.internal.util.IndentingPrintWriter;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.List;
-import java.util.Locale;
-
-
-/**
- * Redirects calls to this service to the instance of the service for the appropriate user.
- */
-class AppWidgetService extends IAppWidgetService.Stub
-{
-    private static final String TAG = "AppWidgetService";
-
-    Context mContext;
-    Locale mLocale;
-    PackageManager mPackageManager;
-    boolean mSafeMode;
-    private final Handler mSaveStateHandler;
-
-    private final SparseArray<AppWidgetServiceImpl> mAppWidgetServices;
-
-    AppWidgetService(Context context) {
-        mContext = context;
-
-        mSaveStateHandler = BackgroundThread.getHandler();
-
-        mAppWidgetServices = new SparseArray<AppWidgetServiceImpl>(5);
-        AppWidgetServiceImpl primary = new AppWidgetServiceImpl(context, 0, mSaveStateHandler);
-        mAppWidgetServices.append(0, primary);
-    }
-
-    public void systemRunning(boolean safeMode) {
-        mSafeMode = safeMode;
-
-        mAppWidgetServices.get(0).systemReady(safeMode);
-
-        // Register for the boot completed broadcast, so we can send the
-        // ENABLE broacasts. If we try to send them now, they time out,
-        // because the system isn't ready to handle them yet.
-        mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL,
-                new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null);
-
-        // Register for configuration changes so we can update the names
-        // of the widgets when the locale changes.
-        mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL,
-                new IntentFilter(Intent.ACTION_CONFIGURATION_CHANGED), null, null);
-
-        // Register for broadcasts about package install, etc., so we can
-        // update the provider list.
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(Intent.ACTION_PACKAGE_ADDED);
-        filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
-        filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
-        filter.addDataScheme("package");
-        mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL,
-                filter, null, null);
-        // Register for events related to sdcard installation.
-        IntentFilter sdFilter = new IntentFilter();
-        sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
-        sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
-        mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL,
-                sdFilter, null, null);
-
-        IntentFilter userFilter = new IntentFilter();
-        userFilter.addAction(Intent.ACTION_USER_REMOVED);
-        userFilter.addAction(Intent.ACTION_USER_STOPPING);
-        mContext.registerReceiver(new BroadcastReceiver() {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) {
-                    onUserRemoved(intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
-                            UserHandle.USER_NULL));
-                } else if (Intent.ACTION_USER_STOPPING.equals(intent.getAction())) {
-                    onUserStopping(intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
-                            UserHandle.USER_NULL));
-                }
-            }
-        }, userFilter);
-    }
-
-    @Override
-    public int allocateAppWidgetId(String packageName, int hostId, int userId)
-            throws RemoteException {
-        return getImplForUser(userId).allocateAppWidgetId(packageName, hostId);
-    }
-
-    @Override
-    public int[] getAppWidgetIdsForHost(int hostId, int userId) throws RemoteException {
-        return getImplForUser(userId).getAppWidgetIdsForHost(hostId);
-    }
-
-    @Override
-    public void deleteAppWidgetId(int appWidgetId, int userId) throws RemoteException {
-        getImplForUser(userId).deleteAppWidgetId(appWidgetId);
-    }
-
-    @Override
-    public void deleteHost(int hostId, int userId) throws RemoteException {
-        getImplForUser(userId).deleteHost(hostId);
-    }
-
-    @Override
-    public void deleteAllHosts(int userId) throws RemoteException {
-        getImplForUser(userId).deleteAllHosts();
-    }
-
-    @Override
-    public void bindAppWidgetId(int appWidgetId, ComponentName provider, Bundle options, int userId)
-            throws RemoteException {
-        getImplForUser(userId).bindAppWidgetId(appWidgetId, provider, options);
-    }
-
-    @Override
-    public boolean bindAppWidgetIdIfAllowed(
-            String packageName, int appWidgetId, ComponentName provider, Bundle options, int userId)
-                    throws RemoteException {
-        return getImplForUser(userId).bindAppWidgetIdIfAllowed(
-                packageName, appWidgetId, provider, options);
-    }
-
-    @Override
-    public boolean hasBindAppWidgetPermission(String packageName, int userId)
-            throws RemoteException {
-        return getImplForUser(userId).hasBindAppWidgetPermission(packageName);
-    }
-
-    @Override
-    public void setBindAppWidgetPermission(String packageName, boolean permission, int userId)
-            throws RemoteException {
-        getImplForUser(userId).setBindAppWidgetPermission(packageName, permission);
-    }
-
-    @Override
-    public void bindRemoteViewsService(int appWidgetId, Intent intent, IBinder connection,
-            int userId) throws RemoteException {
-        getImplForUser(userId).bindRemoteViewsService(appWidgetId, intent, connection);
-    }
-
-    @Override
-    public int[] startListening(IAppWidgetHost host, String packageName, int hostId,
-            List<RemoteViews> updatedViews, int userId) throws RemoteException {
-        return getImplForUser(userId).startListening(host, packageName, hostId, updatedViews);
-    }
-
-    public void onUserRemoved(int userId) {
-        if (userId < 1) return;
-        synchronized (mAppWidgetServices) {
-            AppWidgetServiceImpl impl = mAppWidgetServices.get(userId);
-            mAppWidgetServices.remove(userId);
-
-            if (impl == null) {
-                AppWidgetServiceImpl.getSettingsFile(userId).delete();
-            } else {
-                impl.onUserRemoved();
-            }
-        }
-    }
-
-    public void onUserStopping(int userId) {
-        if (userId < 1) return;
-        synchronized (mAppWidgetServices) {
-            AppWidgetServiceImpl impl = mAppWidgetServices.get(userId);
-            if (impl != null) {
-                mAppWidgetServices.remove(userId);
-                impl.onUserStopping();
-            }
-        }
-    }
-
-    private void checkPermission(int userId) {
-        int realUserId = ActivityManager.handleIncomingUser(
-                Binder.getCallingPid(),
-                Binder.getCallingUid(),
-                userId,
-                false, /* allowAll */
-                true, /* requireFull */
-                this.getClass().getSimpleName(),
-                this.getClass().getPackage().getName());
-    }
-
-    private AppWidgetServiceImpl getImplForUser(int userId) {
-        checkPermission(userId);
-        boolean sendInitial = false;
-        AppWidgetServiceImpl service;
-        synchronized (mAppWidgetServices) {
-            service = mAppWidgetServices.get(userId);
-            if (service == null) {
-                Slog.i(TAG, "Unable to find AppWidgetServiceImpl for user " + userId + ", adding");
-                // TODO: Verify that it's a valid user
-                service = new AppWidgetServiceImpl(mContext, userId, mSaveStateHandler);
-                service.systemReady(mSafeMode);
-                // Assume that BOOT_COMPLETED was received, as this is a non-primary user.
-                mAppWidgetServices.append(userId, service);
-                sendInitial = true;
-            }
-        }
-        if (sendInitial) {
-            service.sendInitialBroadcasts();
-        }
-        return service;
-    }
-
-    @Override
-    public int[] getAppWidgetIds(ComponentName provider, int userId) throws RemoteException {
-        return getImplForUser(userId).getAppWidgetIds(provider);
-    }
-
-    @Override
-    public AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId, int userId)
-            throws RemoteException {
-        return getImplForUser(userId).getAppWidgetInfo(appWidgetId);
-    }
-
-    @Override
-    public RemoteViews getAppWidgetViews(int appWidgetId, int userId) throws RemoteException {
-        return getImplForUser(userId).getAppWidgetViews(appWidgetId);
-    }
-
-    @Override
-    public void updateAppWidgetOptions(int appWidgetId, Bundle options, int userId) {
-        getImplForUser(userId).updateAppWidgetOptions(appWidgetId, options);
-    }
-
-    @Override
-    public Bundle getAppWidgetOptions(int appWidgetId, int userId) {
-        return getImplForUser(userId).getAppWidgetOptions(appWidgetId);
-    }
-
-    @Override
-    public List<AppWidgetProviderInfo> getInstalledProviders(int categoryFilter, int userId)
-            throws RemoteException {
-        return getImplForUser(userId).getInstalledProviders(categoryFilter);
-    }
-
-    @Override
-    public void notifyAppWidgetViewDataChanged(int[] appWidgetIds, int viewId, int userId)
-            throws RemoteException {
-        getImplForUser(userId).notifyAppWidgetViewDataChanged(
-                appWidgetIds, viewId);
-    }
-
-    @Override
-    public void partiallyUpdateAppWidgetIds(int[] appWidgetIds, RemoteViews views, int userId)
-            throws RemoteException {
-        getImplForUser(userId).partiallyUpdateAppWidgetIds(
-                appWidgetIds, views);
-    }
-
-    @Override
-    public void stopListening(int hostId, int userId) throws RemoteException {
-        getImplForUser(userId).stopListening(hostId);
-    }
-
-    @Override
-    public void unbindRemoteViewsService(int appWidgetId, Intent intent, int userId)
-            throws RemoteException {
-        getImplForUser(userId).unbindRemoteViewsService(
-                appWidgetId, intent);
-    }
-
-    @Override
-    public void updateAppWidgetIds(int[] appWidgetIds, RemoteViews views, int userId)
-            throws RemoteException {
-        getImplForUser(userId).updateAppWidgetIds(appWidgetIds, views);
-    }
-
-    @Override
-    public void updateAppWidgetProvider(ComponentName provider, RemoteViews views, int userId)
-            throws RemoteException {
-        getImplForUser(userId).updateAppWidgetProvider(provider, views);
-    }
-
-    @Override
-    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
-
-        // Dump the state of all the app widget providers
-        synchronized (mAppWidgetServices) {
-            IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ");
-            for (int i = 0; i < mAppWidgetServices.size(); i++) {
-                pw.println("User: " + mAppWidgetServices.keyAt(i));
-                ipw.increaseIndent();
-                AppWidgetServiceImpl service = mAppWidgetServices.valueAt(i);
-                service.dump(fd, ipw, args);
-                ipw.decreaseIndent();
-            }
-        }
-    }
-
-    BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
-        public void onReceive(Context context, Intent intent) {
-            String action = intent.getAction();
-            // Slog.d(TAG, "received " + action);
-            if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
-                int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
-                if (userId >= 0) {
-                    getImplForUser(userId).sendInitialBroadcasts();
-                } else {
-                    Slog.w(TAG, "Incorrect user handle supplied in " + intent);
-                }
-            } else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
-                for (int i = 0; i < mAppWidgetServices.size(); i++) {
-                    AppWidgetServiceImpl service = mAppWidgetServices.valueAt(i);
-                    service.onConfigurationChanged();
-                }
-            } else {
-                int sendingUser = getSendingUserId();
-                if (sendingUser == UserHandle.USER_ALL) {
-                    for (int i = 0; i < mAppWidgetServices.size(); i++) {
-                        AppWidgetServiceImpl service = mAppWidgetServices.valueAt(i);
-                        service.onBroadcastReceived(intent);
-                    }
-                } else {
-                    AppWidgetServiceImpl service = mAppWidgetServices.get(sendingUser);
-                    if (service != null) {
-                        service.onBroadcastReceived(intent);
-                    }
-                }
-            }
-        }
-    };
-}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 8a3bc88..a5011af 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -17,6 +17,9 @@
 package com.android.server;
 
 import android.app.ActivityManagerNative;
+import android.app.ActivityThread;
+import android.app.IAlarmManager;
+import android.app.INotificationManager;
 import android.bluetooth.BluetoothAdapter;
 import android.content.ComponentName;
 import android.content.ContentResolver;
@@ -28,8 +31,10 @@
 import android.media.AudioService;
 import android.net.wifi.p2p.WifiP2pService;
 import android.os.Environment;
+import android.os.FactoryTest;
 import android.os.Handler;
-import android.os.HandlerThread;
+import android.os.IBinder;
+import android.os.IPowerManager;
 import android.os.Looper;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -52,13 +57,18 @@
 import com.android.server.accounts.AccountManagerService;
 import com.android.server.am.ActivityManagerService;
 import com.android.server.am.BatteryStatsService;
+import com.android.server.clipboard.ClipboardService;
 import com.android.server.content.ContentService;
+import com.android.server.devicepolicy.DevicePolicyManagerService;
 import com.android.server.display.DisplayManagerService;
 import com.android.server.dreams.DreamManagerService;
 import com.android.server.input.InputManagerService;
+import com.android.server.lights.LightsManager;
+import com.android.server.lights.LightsService;
 import com.android.server.media.MediaRouterService;
 import com.android.server.net.NetworkPolicyManagerService;
 import com.android.server.net.NetworkStatsService;
+import com.android.server.notification.NotificationManagerService;
 import com.android.server.os.SchedulingPolicyService;
 import com.android.server.pm.BackgroundDexOptService;
 import com.android.server.pm.Installer;
@@ -66,9 +76,12 @@
 import com.android.server.pm.UserManagerService;
 import com.android.server.power.PowerManagerService;
 import com.android.server.power.ShutdownThread;
-import com.android.server.print.PrintManagerService;
 import com.android.server.search.SearchManagerService;
+import com.android.server.statusbar.StatusBarManagerService;
+import com.android.server.storage.DeviceStorageMonitorService;
+import com.android.server.twilight.TwilightService;
 import com.android.server.usb.UsbService;
+import com.android.server.wallpaper.WallpaperManagerService;
 import com.android.server.wifi.WifiService;
 import com.android.server.wm.WindowManagerService;
 
@@ -78,62 +91,212 @@
 import java.util.Timer;
 import java.util.TimerTask;
 
-class ServerThread {
+public final class SystemServer {
     private static final String TAG = "SystemServer";
+
     private static final String ENCRYPTING_STATE = "trigger_restart_min_framework";
     private static final String ENCRYPTED_STATE = "1";
 
-    ContentResolver mContentResolver;
+    private static final long SNAPSHOT_INTERVAL = 60 * 60 * 1000; // 1hr
 
-    void reportWtf(String msg, Throwable e) {
+    // The earliest supported time.  We pick one day into 1970, to
+    // give any timezone code room without going into negative time.
+    private static final long EARLIEST_SUPPORTED_TIME = 86400 * 1000;
+
+    /*
+     * Implementation class names. TODO: Move them to a codegen class or load
+     * them from the build system somehow.
+     */
+    private static final String BACKUP_MANAGER_SERVICE_CLASS =
+            "com.android.server.backup.BackupManagerService$Lifecycle";
+    private static final String APPWIDGET_SERVICE_CLASS =
+            "com.android.server.appwidget.AppWidgetService";
+    private static final String PRINT_MANAGER_SERVICE_CLASS =
+            "com.android.server.print.PrintManagerService";
+    private static final String USB_SERVICE_CLASS =
+            "com.android.server.usb.UsbService$Lifecycle";
+    private static final String HDMI_CEC_SERVICE_CLASS =
+            "com.android.server.hdmi.HdmiCecService";
+
+    private final int mFactoryTestMode;
+    private Timer mProfilerSnapshotTimer;
+
+    private Context mSystemContext;
+    private SystemServiceManager mSystemServiceManager;
+
+    // TODO: remove all of these references by improving dependency resolution and boot phases
+    private Installer mInstaller;
+    private PowerManagerService mPowerManagerService;
+    private ActivityManagerService mActivityManagerService;
+    private DisplayManagerService mDisplayManagerService;
+    private ContentResolver mContentResolver;
+
+    /**
+     * Called to initialize native system services.
+     */
+    private static native void nativeInit();
+
+    /**
+     * The main entry point from zygote.
+     */
+    public static void main(String[] args) {
+        new SystemServer().run();
+    }
+
+    public SystemServer() {
+        mFactoryTestMode = FactoryTest.getMode();
+    }
+
+    private void run() {
+        // If a device's clock is before 1970 (before 0), a lot of
+        // APIs crash dealing with negative numbers, notably
+        // java.io.File#setLastModified, so instead we fake it and
+        // hope that time from cell towers or NTP fixes it shortly.
+        if (System.currentTimeMillis() < EARLIEST_SUPPORTED_TIME) {
+            Slog.w(TAG, "System clock is before 1970; setting to 1970.");
+            SystemClock.setCurrentTimeMillis(EARLIEST_SUPPORTED_TIME);
+        }
+
+        // Here we go!
+        Slog.i(TAG, "Entered the Android system server!");
+        EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_SYSTEM_RUN, SystemClock.uptimeMillis());
+
+        // In case the runtime switched since last boot (such as when
+        // the old runtime was removed in an OTA), set the system
+        // property so that it is in sync. We can't do this in
+        // libnativehelper's JniInvocation::Init code where we already
+        // had to fallback to a different runtime because it is
+        // running as root and we need to be the system user to set
+        // the property. http://b/11463182
+        SystemProperties.set("persist.sys.dalvik.vm.lib.1", VMRuntime.getRuntime().vmLibrary());
+
+        // Enable the sampling profiler.
+        if (SamplingProfilerIntegration.isEnabled()) {
+            SamplingProfilerIntegration.start();
+            mProfilerSnapshotTimer = new Timer();
+            mProfilerSnapshotTimer.schedule(new TimerTask() {
+                @Override
+                public void run() {
+                    SamplingProfilerIntegration.writeSnapshot("system_server", null);
+                }
+            }, SNAPSHOT_INTERVAL, SNAPSHOT_INTERVAL);
+        }
+
+        // Mmmmmm... more memory!
+        VMRuntime.getRuntime().clearGrowthLimit();
+
+        // The system server has to run all of the time, so it needs to be
+        // as efficient as possible with its memory usage.
+        VMRuntime.getRuntime().setTargetHeapUtilization(0.8f);
+
+        // Within the system server, it is an error to access Environment paths without
+        // explicitly specifying a user.
+        Environment.setUserRequired(true);
+
+        // Ensure binder calls into the system always run at foreground priority.
+        BinderInternal.disableBackgroundScheduling(true);
+
+        // Prepare the main looper thread (this thread).
+        android.os.Process.setThreadPriority(
+                android.os.Process.THREAD_PRIORITY_FOREGROUND);
+        android.os.Process.setCanSelfBackground(false);
+        Looper.prepareMainLooper();
+
+        // Initialize native services.
+        System.loadLibrary("android_servers");
+        nativeInit();
+
+        // Check whether we failed to shut down last time we tried.
+        // This call may not return.
+        performPendingShutdown();
+
+        // Initialize the system context.
+        createSystemContext();
+
+        // Create the system service manager.
+        mSystemServiceManager = new SystemServiceManager(mSystemContext);
+        LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
+
+        // Start services.
+        try {
+            startBootstrapServices();
+            startCoreServices();
+            startOtherServices();
+        } catch (RuntimeException ex) {
+            Slog.e("System", "******************************************");
+            Slog.e("System", "************ Failure starting system services", ex);
+            throw ex;
+        }
+
+        // For debug builds, log event loop stalls to dropbox for analysis.
+        if (StrictMode.conditionallyEnableDebugLogging()) {
+            Slog.i(TAG, "Enabled StrictMode for system server main thread.");
+        }
+
+        // Loop forever.
+        Looper.loop();
+        throw new RuntimeException("Main thread loop unexpectedly exited");
+    }
+
+    private void reportWtf(String msg, Throwable e) {
         Slog.w(TAG, "***********************************************");
         Log.wtf(TAG, "BOOT FAILURE " + msg, e);
     }
 
-    public void initAndLoop() {
-        EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_SYSTEM_RUN,
-            SystemClock.uptimeMillis());
+    private void performPendingShutdown() {
+        final String shutdownAction = SystemProperties.get(
+                ShutdownThread.SHUTDOWN_ACTION_PROPERTY, "");
+        if (shutdownAction != null && shutdownAction.length() > 0) {
+            boolean reboot = (shutdownAction.charAt(0) == '1');
 
-        Looper.prepareMainLooper();
-
-        android.os.Process.setThreadPriority(
-                android.os.Process.THREAD_PRIORITY_FOREGROUND);
-
-        BinderInternal.disableBackgroundScheduling(true);
-        android.os.Process.setCanSelfBackground(false);
-
-        // Check whether we failed to shut down last time we tried.
-        {
-            final String shutdownAction = SystemProperties.get(
-                    ShutdownThread.SHUTDOWN_ACTION_PROPERTY, "");
-            if (shutdownAction != null && shutdownAction.length() > 0) {
-                boolean reboot = (shutdownAction.charAt(0) == '1');
-
-                final String reason;
-                if (shutdownAction.length() > 1) {
-                    reason = shutdownAction.substring(1, shutdownAction.length());
-                } else {
-                    reason = null;
-                }
-
-                ShutdownThread.rebootOrShutdown(reboot, reason);
+            final String reason;
+            if (shutdownAction.length() > 1) {
+                reason = shutdownAction.substring(1, shutdownAction.length());
+            } else {
+                reason = null;
             }
+
+            ShutdownThread.rebootOrShutdown(reboot, reason);
         }
+    }
 
-        String factoryTestStr = SystemProperties.get("ro.factorytest");
-        int factoryTest = "".equals(factoryTestStr) ? SystemServer.FACTORY_TEST_OFF
-                : Integer.parseInt(factoryTestStr);
-        final boolean headless = "1".equals(SystemProperties.get("ro.config.headless", "0"));
+    private void createSystemContext() {
+        ActivityThread activityThread = ActivityThread.systemMain();
+        mSystemContext = activityThread.getSystemContext();
+        mSystemContext.setTheme(android.R.style.Theme_Holo);
+    }
 
-        Installer installer = null;
+    private void startBootstrapServices() {
+        // Wait for installd to finish starting up so that it has a chance to
+        // create critical directories such as /data/user with the appropriate
+        // permissions.  We need this to complete before we initialize other services.
+        mInstaller = mSystemServiceManager.startService(Installer.class);
+
+        // Power manager needs to be started early because other services need it.
+        // TODO: The conversion to the new pattern is incomplete.  We need to switch
+        // the power manager's dependencies over then we can use boot phases to arrange
+        // initialization order and remove the mPowerManagerService field.
+        mPowerManagerService = mSystemServiceManager.startService(PowerManagerService.class);
+
+        // Activity manager runs the show.
+        mActivityManagerService = mSystemServiceManager.startService(
+                ActivityManagerService.Lifecycle.class).getService();
+    }
+
+    private void startCoreServices() {
+        // Display manager is needed to provide display metrics before package manager
+        // starts up.
+        mDisplayManagerService = mSystemServiceManager.startService(DisplayManagerService.class);
+    }
+
+    private void startOtherServices() {
+        final Context context = mSystemContext;
         AccountManagerService accountManager = null;
         ContentService contentService = null;
-        LightsService lights = null;
-        PowerManagerService power = null;
-        DisplayManagerService display = null;
+        LightsManager lights = null;
         BatteryService battery = null;
         VibratorService vibrator = null;
-        AlarmManagerService alarm = null;
+        IAlarmManager alarm = null;
         MountService mountService = null;
         NetworkManagementService networkManagement = null;
         NetworkStatsService networkStats = null;
@@ -143,14 +306,11 @@
         WifiService wifi = null;
         NsdService serviceDiscovery= null;
         IPackageManager pm = null;
-        Context context = null;
         WindowManagerService wm = null;
         BluetoothManagerService bluetooth = null;
         DockObserver dock = null;
         UsbService usb = null;
         SerialService serial = null;
-        TwilightService twilight = null;
-        UiModeManagerService uiMode = null;
         RecognitionManagerService recognition = null;
         NetworkTimeUpdateService networkTimeUpdater = null;
         CommonTimeManagementService commonTimeMgmtService = null;
@@ -158,48 +318,8 @@
         TelephonyRegistry telephonyRegistry = null;
         ConsumerIrService consumerIr = null;
 
-        // Create a handler thread just for the window manager to enjoy.
-        HandlerThread wmHandlerThread = new HandlerThread("WindowManager");
-        wmHandlerThread.start();
-        Handler wmHandler = new Handler(wmHandlerThread.getLooper());
-        wmHandler.post(new Runnable() {
-            @Override
-            public void run() {
-                //Looper.myLooper().setMessageLogging(new LogPrinter(
-                //        android.util.Log.DEBUG, TAG, android.util.Log.LOG_ID_SYSTEM));
-                android.os.Process.setThreadPriority(
-                        android.os.Process.THREAD_PRIORITY_DISPLAY);
-                android.os.Process.setCanSelfBackground(false);
-
-                // For debug builds, log event loop stalls to dropbox for analysis.
-                if (StrictMode.conditionallyEnableDebugLogging()) {
-                    Slog.i(TAG, "Enabled StrictMode logging for WM Looper");
-                }
-            }
-        });
-
-        // bootstrap services
         boolean onlyCore = false;
         boolean firstBoot = false;
-        try {
-            // Wait for installd to finished starting up so that it has a chance to
-            // create critical directories such as /data/user with the appropriate
-            // permissions.  We need this to complete before we initialize other services.
-            Slog.i(TAG, "Waiting for installd to be ready.");
-            installer = new Installer();
-            installer.ping();
-
-            Slog.i(TAG, "Power Manager");
-            power = new PowerManagerService();
-            ServiceManager.addService(Context.POWER_SERVICE, power);
-
-            Slog.i(TAG, "Activity Manager");
-            context = ActivityManagerService.main(factoryTest);
-        } catch (RuntimeException e) {
-            Slog.e("System", "******************************************");
-            Slog.e("System", "************ Failure starting bootstrap service", e);
-        }
-
         boolean disableStorage = SystemProperties.getBoolean("config.disable_storage", false);
         boolean disableMedia = SystemProperties.getBoolean("config.disable_media", false);
         boolean disableBluetooth = SystemProperties.getBoolean("config.disable_bluetooth", false);
@@ -210,10 +330,6 @@
         boolean disableNetwork = SystemProperties.getBoolean("config.disable_network", false);
 
         try {
-            Slog.i(TAG, "Display Manager");
-            display = new DisplayManagerService(context, wmHandler);
-            ServiceManager.addService(Context.DISPLAY_SERVICE, display, true);
-
             Slog.i(TAG, "Telephony Registry");
             telephonyRegistry = new TelephonyRegistry(context);
             ServiceManager.addService("telephony.registry", telephonyRegistry);
@@ -223,10 +339,8 @@
 
             AttributeCache.init(context);
 
-            if (!display.waitForDefaultDisplay()) {
-                reportWtf("Timeout waiting for default display to be initialized.",
-                        new Throwable());
-            }
+            // We need the default display before we can initialize the package manager.
+            mSystemServiceManager.startBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY);
 
             Slog.i(TAG, "Package Manager");
             // Only run "core" apps if we're encrypting the device.
@@ -239,15 +353,15 @@
                 onlyCore = true;
             }
 
-            pm = PackageManagerService.main(context, installer,
-                    factoryTest != SystemServer.FACTORY_TEST_OFF,
+            pm = PackageManagerService.main(context, mInstaller,
+                    mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF,
                     onlyCore);
             try {
                 firstBoot = pm.isFirstBoot();
             } catch (RemoteException e) {
             }
 
-            ActivityManagerService.setSystemProcess();
+            mActivityManagerService.setSystemProcess();
 
             Slog.i(TAG, "Entropy Mixer");
             ServiceManager.addService("entropy", new EntropyMixer(context));
@@ -270,13 +384,13 @@
 
             Slog.i(TAG, "Content Manager");
             contentService = ContentService.main(context,
-                    factoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL);
+                    mFactoryTestMode == FactoryTest.FACTORY_TEST_LOW_LEVEL);
 
             Slog.i(TAG, "System Content Providers");
-            ActivityManagerService.installSystemProviders();
+            mActivityManagerService.installSystemProviders();
 
-            Slog.i(TAG, "Lights Service");
-            lights = new LightsService(context);
+            mSystemServiceManager.startService(LightsService.class);
+            lights = LocalServices.getService(LightsManager.class);
 
             Slog.i(TAG, "Battery Service");
             battery = new BatteryService(context, lights);
@@ -286,49 +400,49 @@
             vibrator = new VibratorService(context);
             ServiceManager.addService("vibrator", vibrator);
 
+            // TODO: use boot phase
+            // only initialize the power service after we have started the
+            // lights service, content providers and the battery service.
+            mPowerManagerService.init(lights, battery,
+                    BatteryStatsService.getService(),
+                    mActivityManagerService.getAppOpsService());
+
             Slog.i(TAG, "Consumer IR Service");
             consumerIr = new ConsumerIrService(context);
             ServiceManager.addService(Context.CONSUMER_IR_SERVICE, consumerIr);
 
-            // only initialize the power service after we have started the
-            // lights service, content providers and the battery service.
-            power.init(context, lights, ActivityManagerService.self(), battery,
-                    BatteryStatsService.getService(),
-                    ActivityManagerService.self().getAppOpsService(), display);
-
-            Slog.i(TAG, "Alarm Manager");
-            alarm = new AlarmManagerService(context);
-            ServiceManager.addService(Context.ALARM_SERVICE, alarm);
+            mSystemServiceManager.startService(AlarmManagerService.class);
+            alarm = IAlarmManager.Stub.asInterface(
+                    ServiceManager.getService(Context.ALARM_SERVICE));
 
             Slog.i(TAG, "Init Watchdog");
-            Watchdog.getInstance().init(context, battery, power, alarm,
-                    ActivityManagerService.self());
-            Watchdog.getInstance().addThread(wmHandler, "WindowManager thread");
+            final Watchdog watchdog = Watchdog.getInstance();
+            watchdog.init(context, mActivityManagerService);
 
             Slog.i(TAG, "Input Manager");
-            inputManager = new InputManagerService(context, wmHandler);
+            inputManager = new InputManagerService(context);
 
             Slog.i(TAG, "Window Manager");
-            wm = WindowManagerService.main(context, power, display, inputManager,
-                    wmHandler, factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL,
+            wm = WindowManagerService.main(context, inputManager,
+                    mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
                     !firstBoot, onlyCore);
             ServiceManager.addService(Context.WINDOW_SERVICE, wm);
             ServiceManager.addService(Context.INPUT_SERVICE, inputManager);
 
-            ActivityManagerService.self().setWindowManager(wm);
+            mActivityManagerService.setWindowManager(wm);
 
             inputManager.setWindowManagerCallbacks(wm.getInputMonitor());
             inputManager.start();
 
-            display.setWindowManager(wm);
-            display.setInputManager(inputManager);
+            // TODO: Use service dependencies instead.
+            mDisplayManagerService.windowManagerAndInputReady();
 
             // Skip Bluetooth if we have an emulator kernel
             // TODO: Use a more reliable check to see if this product should
             // support Bluetooth - see bug 988521
             if (SystemProperties.get("ro.kernel.qemu").equals("1")) {
                 Slog.i(TAG, "No Bluetooh Service (emulator)");
-            } else if (factoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) {
+            } else if (mFactoryTestMode == FactoryTest.FACTORY_TEST_LOW_LEVEL) {
                 Slog.i(TAG, "No Bluetooth Service (factory test)");
             } else if (!context.getPackageManager().hasSystemFeature
                        (PackageManager.FEATURE_BLUETOOTH)) {
@@ -345,23 +459,19 @@
             Slog.e("System", "************ Failure starting core service", e);
         }
 
-        DevicePolicyManagerService devicePolicy = null;
         StatusBarManagerService statusBar = null;
+        INotificationManager notification = null;
         InputMethodManagerService imm = null;
-        AppWidgetService appWidget = null;
-        NotificationManagerService notification = null;
         WallpaperManagerService wallpaper = null;
         LocationManagerService location = null;
         CountryDetectorService countryDetector = null;
         TextServicesManagerService tsms = null;
         LockSettingsService lockSettings = null;
-        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) {
+        if (mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
             //if (!disableNonCoreServices) { // TODO: View depends on these; mock them?
             if (true) {
                 try {
@@ -398,11 +508,11 @@
             ActivityManagerNative.getDefault().showBootMessage(
                     context.getResources().getText(
                             com.android.internal.R.string.android_upgrading_starting_apps),
-                            false);
+                    false);
         } catch (RemoteException e) {
         }
 
-        if (factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
+        if (mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
             if (!disableStorage &&
                 !"0".equals(SystemProperties.get("system_init.startmountservice"))) {
                 try {
@@ -428,9 +538,9 @@
                 }
 
                 try {
-                    Slog.i(TAG, "Device Policy");
-                    devicePolicy = new DevicePolicyManagerService(context);
-                    ServiceManager.addService(Context.DEVICE_POLICY_SERVICE, devicePolicy);
+                    // Always start the Device Policy Manager, so that the API is compatible with
+                    // API8.
+                    mSystemServiceManager.startService(DevicePolicyManagerService.Lifecycle.class);
                 } catch (Throwable e) {
                     reportWtf("starting DevicePolicyService", e);
                 }
@@ -488,7 +598,8 @@
                 try {
                     Slog.i(TAG, "NetworkPolicy Service");
                     networkPolicy = new NetworkPolicyManagerService(
-                            context, ActivityManagerService.self(), power,
+                            context, mActivityManagerService,
+                            (IPowerManager)ServiceManager.getService(Context.POWER_SERVICE),
                             networkStats, networkManagement);
                     ServiceManager.addService(Context.NETWORK_POLICY_SERVICE, networkPolicy);
                 } catch (Throwable e) {
@@ -568,22 +679,12 @@
                 reportWtf("making Content Service ready", e);
             }
 
-            try {
-                Slog.i(TAG, "Notification Manager");
-                notification = new NotificationManagerService(context, statusBar, lights);
-                ServiceManager.addService(Context.NOTIFICATION_SERVICE, notification);
-                networkPolicy.bindNotificationManager(notification);
-            } catch (Throwable e) {
-                reportWtf("starting Notification Manager", e);
-            }
+            mSystemServiceManager.startService(NotificationManagerService.class);
+            notification = INotificationManager.Stub.asInterface(
+                    ServiceManager.getService(Context.NOTIFICATION_SERVICE));
+            networkPolicy.bindNotificationManager(notification);
 
-            try {
-                Slog.i(TAG, "Device Storage Monitor");
-                ServiceManager.addService(DeviceStorageMonitorService.SERVICE,
-                        new DeviceStorageMonitorService(context));
-            } catch (Throwable e) {
-                reportWtf("starting DeviceStorageMonitor service", e);
-            }
+            mSystemServiceManager.startService(DeviceStorageMonitorService.class);
 
             if (!disableLocation) {
                 try {
@@ -625,10 +726,8 @@
                         R.bool.config_enableWallpaperService)) {
                 try {
                     Slog.i(TAG, "Wallpaper Service");
-                    if (!headless) {
-                        wallpaper = new WallpaperManagerService(context);
-                        ServiceManager.addService(Context.WALLPAPER_SERVICE, wallpaper);
-                    }
+                    wallpaper = new WallpaperManagerService(context);
+                    ServiceManager.addService(Context.WALLPAPER_SERVICE, wallpaper);
                 } catch (Throwable e) {
                     reportWtf("starting Wallpaper Service", e);
                 }
@@ -666,10 +765,11 @@
 
             if (!disableNonCoreServices) {
                 try {
-                    Slog.i(TAG, "USB Service");
-                    // Manage USB host and device support
-                    usb = new UsbService(context);
-                    ServiceManager.addService(Context.USB_SERVICE, usb);
+                    if (pm.hasSystemFeature(PackageManager.FEATURE_USB_HOST) ||
+                            pm.hasSystemFeature(PackageManager.FEATURE_USB_ACCESSORY)) {
+                        // Manage USB host and device support
+                        mSystemServiceManager.startService(USB_SERVICE_CLASS);
+                    }
                 } catch (Throwable e) {
                     reportWtf("starting UsbService", e);
                 }
@@ -684,34 +784,23 @@
                 }
             }
 
-            try {
-                Slog.i(TAG, "Twilight Service");
-                twilight = new TwilightService(context);
-            } catch (Throwable e) {
-                reportWtf("starting TwilightService", e);
-            }
+            mSystemServiceManager.startService(TwilightService.class);
 
-            try {
-                Slog.i(TAG, "UI Mode Manager Service");
-                // Listen for UI mode changes
-                uiMode = new UiModeManagerService(context, twilight);
-            } catch (Throwable e) {
-                reportWtf("starting UiModeManagerService", e);
-            }
+            mSystemServiceManager.startService(UiModeManagerService.class);
 
             if (!disableNonCoreServices) {
                 try {
-                    Slog.i(TAG, "Backup Service");
-                    ServiceManager.addService(Context.BACKUP_SERVICE,
-                            new BackupManagerService(context));
+                    if (pm.hasSystemFeature(PackageManager.FEATURE_BACKUP)) {
+                        mSystemServiceManager.startService(BACKUP_MANAGER_SERVICE_CLASS);
+                    }
                 } catch (Throwable e) {
                     Slog.e(TAG, "Failure starting Backup Service", e);
                 }
 
                 try {
-                    Slog.i(TAG, "AppWidget Service");
-                    appWidget = new AppWidgetService(context);
-                    ServiceManager.addService(Context.APPWIDGET_SERVICE, appWidget);
+                    if (pm.hasSystemFeature(PackageManager.FEATURE_APP_WIDGETS)) {
+                        mSystemServiceManager.startService(APPWIDGET_SERVICE_CLASS);
+                    }
                 } catch (Throwable e) {
                     reportWtf("starting AppWidget Service", e);
                 }
@@ -771,16 +860,9 @@
                 }
             }
 
-            if (!disableNonCoreServices && 
-                context.getResources().getBoolean(R.bool.config_dreamsSupported)) {
-                try {
-                    Slog.i(TAG, "Dreams Service");
-                    // Dreams (interactive idle-time views, a/k/a screen savers)
-                    dreamy = new DreamManagerService(context, wmHandler);
-                    ServiceManager.addService(DreamService.DREAM_SERVICE, dreamy);
-                } catch (Throwable e) {
-                    reportWtf("starting DreamManagerService", e);
-                }
+            if (!disableNonCoreServices) {
+                // Dreams (interactive idle-time views, a/k/a screen savers, and doze mode)
+                mSystemServiceManager.startService(DreamManagerService.class);
             }
 
             if (!disableNonCoreServices) {
@@ -801,13 +883,19 @@
             }
 
             try {
-                Slog.i(TAG, "Print Service");
-                printManager = new PrintManagerService(context);
-                ServiceManager.addService(Context.PRINT_SERVICE, printManager);
+                if (pm.hasSystemFeature(PackageManager.FEATURE_PRINTING)) {
+                    mSystemServiceManager.startService(PRINT_MANAGER_SERVICE_CLASS);
+                }
             } catch (Throwable e) {
                 reportWtf("starting Print Service", e);
             }
 
+            try {
+                mSystemServiceManager.startService(HDMI_CEC_SERVICE_CLASS);
+            } catch (Throwable e) {
+                reportWtf("starting HdmiCec Service", e);
+            }
+
             if (!disableNonCoreServices) {
                 try {
                     Slog.i(TAG, "Media Router Service");
@@ -830,9 +918,7 @@
         // we are in safe mode.
         final boolean safeMode = wm.detectSafeMode();
         if (safeMode) {
-            ActivityManagerService.self().enterSafeMode();
-            // Post the safe mode state in the Zygote class
-            SystemServer.inSafeMode = true;
+            mActivityManagerService.enterSafeMode();
             // Disable the JIT for the system_server process
             VMRuntime.getRuntime().disableJitCompilation();
         } else {
@@ -856,21 +942,10 @@
             }
         }
 
-        if (devicePolicy != null) {
-            try {
-                devicePolicy.systemReady();
-            } catch (Throwable e) {
-                reportWtf("making Device Policy Service ready", e);
-            }
-        }
+        // Needed by DevicePolicyManager for initialization
+        mSystemServiceManager.startBootPhase(SystemService.PHASE_LOCK_SETTINGS_READY);
 
-        if (notification != null) {
-            try {
-                notification.systemReady();
-            } catch (Throwable e) {
-                reportWtf("making Notification Service ready", e);
-            }
-        }
+        mSystemServiceManager.startBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);
 
         try {
             wm.systemReady();
@@ -879,7 +954,7 @@
         }
 
         if (safeMode) {
-            ActivityManagerService.self().showSafeModeOverlay();
+            mActivityManagerService.showSafeModeOverlay();
         }
 
         // Update the configuration for this context by hand, because we're going
@@ -892,7 +967,8 @@
         context.getResources().updateConfiguration(config, metrics);
 
         try {
-            power.systemReady(twilight, dreamy);
+            // TODO: use boot phase
+            mPowerManagerService.systemReady();
         } catch (Throwable e) {
             reportWtf("making Power Manager Service ready", e);
         }
@@ -904,13 +980,13 @@
         }
 
         try {
-            display.systemReady(safeMode, onlyCore);
+            // TODO: use boot phase and communicate these flags some other way
+            mDisplayManagerService.systemReady(safeMode, onlyCore);
         } catch (Throwable e) {
             reportWtf("making Display Manager Service ready", e);
         }
 
         // These are needed to propagate to the runnable below.
-        final Context contextF = context;
         final MountService mountServiceF = mountService;
         final BatteryService batteryF = battery;
         final NetworkManagementService networkManagementF = networkManagement;
@@ -918,10 +994,6 @@
         final NetworkPolicyManagerService networkPolicyF = networkPolicy;
         final ConnectivityService connectivityF = connectivity;
         final DockObserver dockF = dock;
-        final UsbService usbF = usb;
-        final TwilightService twilightF = twilight;
-        final UiModeManagerService uiModeF = uiMode;
-        final AppWidgetService appWidgetF = appWidget;
         final WallpaperManagerService wallpaperF = wallpaper;
         final InputMethodManagerService immF = imm;
         final RecognitionManagerService recognitionF = recognition;
@@ -931,11 +1003,9 @@
         final CommonTimeManagementService commonTimeMgmtServiceF = commonTimeMgmtService;
         final TextServicesManagerService textServiceManagerServiceF = tsms;
         final StatusBarManagerService statusBarF = statusBar;
-        final DreamManagerService dreamyF = dreamy;
         final AssetAtlasService atlasF = atlas;
         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
@@ -943,17 +1013,22 @@
         // where third party code can really run (but before it has actually
         // started launching the initial applications), for us to complete our
         // initialization.
-        ActivityManagerService.self().systemReady(new Runnable() {
+        mActivityManagerService.systemReady(new Runnable() {
+            @Override
             public void run() {
                 Slog.i(TAG, "Making services ready");
+                mSystemServiceManager.startBootPhase(
+                        SystemService.PHASE_ACTIVITY_MANAGER_READY);
 
                 try {
-                    ActivityManagerService.self().startObservingNativeCrashes();
+                    mActivityManagerService.startObservingNativeCrashes();
                 } catch (Throwable e) {
                     reportWtf("observing native crashes", e);
                 }
-                if (!headless) {
-                    startSystemUi(contextF);
+                try {
+                    startSystemUi(context);
+                } catch (Throwable e) {
+                    reportWtf("starting System UI", e);
                 }
                 try {
                     if (mountServiceF != null) mountServiceF.systemReady();
@@ -991,21 +1066,6 @@
                     reportWtf("making Dock Service ready", e);
                 }
                 try {
-                    if (usbF != null) usbF.systemReady();
-                } catch (Throwable e) {
-                    reportWtf("making USB Service ready", e);
-                }
-                try {
-                    if (twilightF != null) twilightF.systemReady();
-                } catch (Throwable e) {
-                    reportWtf("makin Twilight Service ready", e);
-                }
-                try {
-                    if (uiModeF != null) uiModeF.systemReady();
-                } catch (Throwable e) {
-                    reportWtf("making UI Mode Service ready", e);
-                }
-                try {
                     if (recognitionF != null) recognitionF.systemReady();
                 } catch (Throwable e) {
                     reportWtf("making Recognition Service ready", e);
@@ -1014,13 +1074,10 @@
 
                 // It is now okay to let the various system services start their
                 // third party code...
+                mSystemServiceManager.startBootPhase(
+                        SystemService.PHASE_THIRD_PARTY_APPS_CAN_START);
 
                 try {
-                    if (appWidgetF != null) appWidgetF.systemRunning(safeMode);
-                } catch (Throwable e) {
-                    reportWtf("Notifying AppWidgetService running", e);
-                }
-                try {
                     if (wallpaperF != null) wallpaperF.systemRunning();
                 } catch (Throwable e) {
                     reportWtf("Notifying WallpaperService running", e);
@@ -1046,7 +1103,9 @@
                     reportWtf("Notifying NetworkTimeService running", e);
                 }
                 try {
-                    if (commonTimeMgmtServiceF != null) commonTimeMgmtServiceF.systemRunning();
+                    if (commonTimeMgmtServiceF != null) {
+                        commonTimeMgmtServiceF.systemRunning();
+                    }
                 } catch (Throwable e) {
                     reportWtf("Notifying CommonTimeManagementService running", e);
                 }
@@ -1057,11 +1116,6 @@
                     reportWtf("Notifying TextServicesManagerService running", e);
                 }
                 try {
-                    if (dreamyF != null) dreamyF.systemRunning();
-                } catch (Throwable e) {
-                    reportWtf("Notifying DreamManagerService running", e);
-                }
-                try {
                     if (atlasF != null) atlasF.systemRunning();
                 } catch (Throwable e) {
                     reportWtf("Notifying AssetAtlasService running", e);
@@ -1072,34 +1126,20 @@
                 } catch (Throwable e) {
                     reportWtf("Notifying InputManagerService running", e);
                 }
-
                 try {
                     if (telephonyRegistryF != null) telephonyRegistryF.systemRunning();
                 } catch (Throwable e) {
                     reportWtf("Notifying TelephonyRegistry running", e);
                 }
-
-                try {
-                    if (printManagerF != null) printManagerF.systemRuning();
-                } catch (Throwable e) {
-                    reportWtf("Notifying PrintManagerService running", e);
-                }
-
                 try {
                     if (mediaRouterF != null) mediaRouterF.systemRunning();
                 } catch (Throwable e) {
                     reportWtf("Notifying MediaRouterService running", e);
                 }
+
+                mSystemServiceManager.startBootPhase(SystemService.PHASE_BOOT_COMPLETE);
             }
         });
-
-        // For debug builds, log event loop stalls to dropbox for analysis.
-        if (StrictMode.conditionallyEnableDebugLogging()) {
-            Slog.i(TAG, "Enabled StrictMode for system server main thread.");
-        }
-
-        Looper.loop();
-        Slog.d(TAG, "System ServerThread is exiting!");
     }
 
     static final void startSystemUi(Context context) {
@@ -1110,85 +1150,3 @@
         context.startServiceAsUser(intent, UserHandle.OWNER);
     }
 }
-
-public class SystemServer {
-    private static final String TAG = "SystemServer";
-
-    public static final int FACTORY_TEST_OFF = 0;
-    public static final int FACTORY_TEST_LOW_LEVEL = 1;
-    public static final int FACTORY_TEST_HIGH_LEVEL = 2;
-
-    static Timer timer;
-    static final long SNAPSHOT_INTERVAL = 60 * 60 * 1000; // 1hr
-
-    // The earliest supported time.  We pick one day into 1970, to
-    // give any timezone code room without going into negative time.
-    private static final long EARLIEST_SUPPORTED_TIME = 86400 * 1000;
-
-   /**
-    * When set, all subsequent apps will be launched in safe mode.
-    */
-    public static boolean inSafeMode;
-
-    /**
-     * Called to initialize native system services.
-     */
-    private static native void nativeInit();
-
-    public static void main(String[] args) {
-
-        /*
-         * In case the runtime switched since last boot (such as when
-         * the old runtime was removed in an OTA), set the system
-         * property so that it is in sync. We can't do this in
-         * libnativehelper's JniInvocation::Init code where we already
-         * had to fallback to a different runtime because it is
-         * running as root and we need to be the system user to set
-         * the property. http://b/11463182
-         */
-        SystemProperties.set("persist.sys.dalvik.vm.lib.1",
-                             VMRuntime.getRuntime().vmLibrary());
-
-        if (System.currentTimeMillis() < EARLIEST_SUPPORTED_TIME) {
-            // If a device's clock is before 1970 (before 0), a lot of
-            // APIs crash dealing with negative numbers, notably
-            // java.io.File#setLastModified, so instead we fake it and
-            // hope that time from cell towers or NTP fixes it
-            // shortly.
-            Slog.w(TAG, "System clock is before 1970; setting to 1970.");
-            SystemClock.setCurrentTimeMillis(EARLIEST_SUPPORTED_TIME);
-        }
-
-        if (SamplingProfilerIntegration.isEnabled()) {
-            SamplingProfilerIntegration.start();
-            timer = new Timer();
-            timer.schedule(new TimerTask() {
-                @Override
-                public void run() {
-                    SamplingProfilerIntegration.writeSnapshot("system_server", null);
-                }
-            }, SNAPSHOT_INTERVAL, SNAPSHOT_INTERVAL);
-        }
-
-        // Mmmmmm... more memory!
-        dalvik.system.VMRuntime.getRuntime().clearGrowthLimit();
-
-        // The system server has to run all of the time, so it needs to be
-        // as efficient as possible with its memory usage.
-        VMRuntime.getRuntime().setTargetHeapUtilization(0.8f);
-
-        Environment.setUserRequired(true);
-
-        System.loadLibrary("android_servers");
-
-        Slog.i(TAG, "Entered the Android system server!");
-
-        // Initialize native services.
-        nativeInit();
-
-        // This used to be its own separate thread, but now it is
-        // just the loop we run on the main thread.
-        ServerThread thr = new ServerThread();
-        thr.initAndLoop();
-    }
-}
diff --git a/services/java/com/android/server/display/DisplayManagerService.java b/services/java/com/android/server/display/DisplayManagerService.java
deleted file mode 100644
index bcb677f..0000000
--- a/services/java/com/android/server/display/DisplayManagerService.java
+++ /dev/null
@@ -1,1331 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.display;
-
-import com.android.internal.util.IndentingPrintWriter;
-
-import android.Manifest;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.hardware.display.DisplayManager;
-import android.hardware.display.DisplayManagerGlobal;
-import android.hardware.display.IDisplayManager;
-import android.hardware.display.IDisplayManagerCallback;
-import android.hardware.display.WifiDisplayStatus;
-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.os.SystemProperties;
-import android.text.TextUtils;
-import android.util.Log;
-import android.util.Slog;
-import android.util.SparseArray;
-import android.view.Display;
-import android.view.DisplayInfo;
-import android.view.Surface;
-
-import com.android.server.UiThread;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.concurrent.CopyOnWriteArrayList;
-
-/**
- * Manages attached displays.
- * <p>
- * The {@link DisplayManagerService} manages the global lifecycle of displays,
- * decides how to configure logical displays based on the physical display devices currently
- * attached, sends notifications to the system and to applications when the state
- * changes, and so on.
- * </p><p>
- * The display manager service relies on a collection of {@link DisplayAdapter} components,
- * for discovering and configuring physical display devices attached to the system.
- * There are separate display adapters for each manner that devices are attached:
- * one display adapter for built-in local displays, one for simulated non-functional
- * displays when the system is headless, one for simulated overlay displays used for
- * development, one for wifi displays, etc.
- * </p><p>
- * Display adapters are only weakly coupled to the display manager service.
- * Display adapters communicate changes in display device state to the display manager
- * service asynchronously via a {@link DisplayAdapter.Listener} registered
- * by the display manager service.  This separation of concerns is important for
- * two main reasons.  First, it neatly encapsulates the responsibilities of these
- * two classes: display adapters handle individual display devices whereas
- * the display manager service handles the global state.  Second, it eliminates
- * the potential for deadlocks resulting from asynchronous display device discovery.
- * </p>
- *
- * <h3>Synchronization</h3>
- * <p>
- * Because the display manager may be accessed by multiple threads, the synchronization
- * story gets a little complicated.  In particular, the window manager may call into
- * the display manager while holding a surface transaction with the expectation that
- * it can apply changes immediately.  Unfortunately, that means we can't just do
- * everything asynchronously (*grump*).
- * </p><p>
- * To make this work, all of the objects that belong to the display manager must
- * use the same lock.  We call this lock the synchronization root and it has a unique
- * type {@link DisplayManagerService.SyncRoot}.  Methods that require this lock are
- * named with the "Locked" suffix.
- * </p><p>
- * Where things get tricky is that the display manager is not allowed to make
- * any potentially reentrant calls, especially into the window manager.  We generally
- * avoid this by making all potentially reentrant out-calls asynchronous.
- * </p>
- */
-public final class DisplayManagerService extends IDisplayManager.Stub {
-    private static final String TAG = "DisplayManagerService";
-    private static final boolean DEBUG = false;
-
-    // When this system property is set to 0, WFD is forcibly disabled on boot.
-    // When this system property is set to 1, WFD is forcibly enabled on boot.
-    // Otherwise WFD is enabled according to the value of config_enableWifiDisplay.
-    private static final String FORCE_WIFI_DISPLAY_ENABLE = "persist.debug.wfd.enable";
-
-    private static final String SYSTEM_HEADLESS = "ro.config.headless";
-    private static final long WAIT_FOR_DEFAULT_DISPLAY_TIMEOUT = 10000;
-
-    private static final int MSG_REGISTER_DEFAULT_DISPLAY_ADAPTER = 1;
-    private static final int MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS = 2;
-    private static final int MSG_DELIVER_DISPLAY_EVENT = 3;
-    private static final int MSG_REQUEST_TRAVERSAL = 4;
-    private static final int MSG_UPDATE_VIEWPORT = 5;
-
-    private static final int DISPLAY_BLANK_STATE_UNKNOWN = 0;
-    private static final int DISPLAY_BLANK_STATE_BLANKED = 1;
-    private static final int DISPLAY_BLANK_STATE_UNBLANKED = 2;
-
-    private final Context mContext;
-    private final boolean mHeadless;
-    private final DisplayManagerHandler mHandler;
-    private final Handler mUiHandler;
-    private final DisplayAdapterListener mDisplayAdapterListener;
-    private WindowManagerFuncs mWindowManagerFuncs;
-    private InputManagerFuncs mInputManagerFuncs;
-
-    // The synchronization root for the display manager.
-    // This lock guards most of the display manager's state.
-    // NOTE: This is synchronized on while holding WindowManagerService.mWindowMap so never call
-    // into WindowManagerService methods that require mWindowMap while holding this unless you are
-    // very very sure that no deadlock can occur.
-    private final SyncRoot mSyncRoot = new SyncRoot();
-
-    // True if in safe mode.
-    // This option may disable certain display adapters.
-    public boolean mSafeMode;
-
-    // True if we are in a special boot mode where only core applications and
-    // services should be started.  This option may disable certain display adapters.
-    public boolean mOnlyCore;
-
-    // True if the display manager service should pretend there is only one display
-    // and only tell applications about the existence of the default logical display.
-    // The display manager can still mirror content to secondary displays but applications
-    // cannot present unique content on those displays.
-    // Used for demonstration purposes only.
-    private final boolean mSingleDisplayDemoMode;
-
-    // All callback records indexed by calling process id.
-    public final SparseArray<CallbackRecord> mCallbacks =
-            new SparseArray<CallbackRecord>();
-
-    // List of all currently registered display adapters.
-    private final ArrayList<DisplayAdapter> mDisplayAdapters = new ArrayList<DisplayAdapter>();
-
-    // List of all currently connected display devices.
-    private final ArrayList<DisplayDevice> mDisplayDevices = new ArrayList<DisplayDevice>();
-
-    // List of all logical displays indexed by logical display id.
-    private final SparseArray<LogicalDisplay> mLogicalDisplays =
-            new SparseArray<LogicalDisplay>();
-    private int mNextNonDefaultDisplayId = Display.DEFAULT_DISPLAY + 1;
-
-    // List of all display transaction listeners.
-    private final CopyOnWriteArrayList<DisplayTransactionListener> mDisplayTransactionListeners =
-            new CopyOnWriteArrayList<DisplayTransactionListener>();
-
-    // Set to true if all displays have been blanked by the power manager.
-    private int mAllDisplayBlankStateFromPowerManager = DISPLAY_BLANK_STATE_UNKNOWN;
-
-    // Set to true when there are pending display changes that have yet to be applied
-    // to the surface flinger state.
-    private boolean mPendingTraversal;
-
-    // The Wifi display adapter, or null if not registered.
-    private WifiDisplayAdapter mWifiDisplayAdapter;
-
-    // The number of active wifi display scan requests.
-    private int mWifiDisplayScanRequestCount;
-
-    // The virtual display adapter, or null if not registered.
-    private VirtualDisplayAdapter mVirtualDisplayAdapter;
-
-    // Viewports of the default display and the display that should receive touch
-    // input from an external source.  Used by the input system.
-    private final DisplayViewport mDefaultViewport = new DisplayViewport();
-    private final DisplayViewport mExternalTouchViewport = new DisplayViewport();
-
-    // Persistent data store for all internal settings maintained by the display manager service.
-    private final PersistentDataStore mPersistentDataStore = new PersistentDataStore();
-
-    // Temporary callback list, used when sending display events to applications.
-    // May be used outside of the lock but only on the handler thread.
-    private final ArrayList<CallbackRecord> mTempCallbacks = new ArrayList<CallbackRecord>();
-
-    // Temporary display info, used for comparing display configurations.
-    private final DisplayInfo mTempDisplayInfo = new DisplayInfo();
-
-    // Temporary viewports, used when sending new viewport information to the
-    // input system.  May be used outside of the lock but only on the handler thread.
-    private final DisplayViewport mTempDefaultViewport = new DisplayViewport();
-    private final DisplayViewport mTempExternalTouchViewport = new DisplayViewport();
-
-    public DisplayManagerService(Context context, Handler mainHandler) {
-        mContext = context;
-        mHeadless = SystemProperties.get(SYSTEM_HEADLESS).equals("1");
-
-        mHandler = new DisplayManagerHandler(mainHandler.getLooper());
-        mUiHandler = UiThread.getHandler();
-        mDisplayAdapterListener = new DisplayAdapterListener();
-        mSingleDisplayDemoMode = SystemProperties.getBoolean("persist.demo.singledisplay", false);
-
-        mHandler.sendEmptyMessage(MSG_REGISTER_DEFAULT_DISPLAY_ADAPTER);
-    }
-
-    /**
-     * Pauses the boot process to wait for the first display to be initialized.
-     */
-    public boolean waitForDefaultDisplay() {
-        synchronized (mSyncRoot) {
-            long timeout = SystemClock.uptimeMillis() + WAIT_FOR_DEFAULT_DISPLAY_TIMEOUT;
-            while (mLogicalDisplays.get(Display.DEFAULT_DISPLAY) == null) {
-                long delay = timeout - SystemClock.uptimeMillis();
-                if (delay <= 0) {
-                    return false;
-                }
-                if (DEBUG) {
-                    Slog.d(TAG, "waitForDefaultDisplay: waiting, timeout=" + delay);
-                }
-                try {
-                    mSyncRoot.wait(delay);
-                } catch (InterruptedException ex) {
-                }
-            }
-        }
-        return true;
-    }
-
-    /**
-     * Called during initialization to associate the display manager with the
-     * window manager.
-     */
-    public void setWindowManager(WindowManagerFuncs windowManagerFuncs) {
-        synchronized (mSyncRoot) {
-            mWindowManagerFuncs = windowManagerFuncs;
-            scheduleTraversalLocked(false);
-        }
-    }
-
-    /**
-     * Called during initialization to associate the display manager with the
-     * input manager.
-     */
-    public void setInputManager(InputManagerFuncs inputManagerFuncs) {
-        synchronized (mSyncRoot) {
-            mInputManagerFuncs = inputManagerFuncs;
-            scheduleTraversalLocked(false);
-        }
-    }
-
-    /**
-     * Called when the system is ready to go.
-     */
-    public void systemReady(boolean safeMode, boolean onlyCore) {
-        synchronized (mSyncRoot) {
-            mSafeMode = safeMode;
-            mOnlyCore = onlyCore;
-        }
-
-        mHandler.sendEmptyMessage(MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS);
-    }
-
-    /**
-     * Returns true if the device is headless.
-     *
-     * @return True if the device is headless.
-     */
-    public boolean isHeadless() {
-        return mHeadless;
-    }
-
-    /**
-     * Registers a display transaction listener to provide the client a chance to
-     * update its surfaces within the same transaction as any display layout updates.
-     *
-     * @param listener The listener to register.
-     */
-    public void registerDisplayTransactionListener(DisplayTransactionListener listener) {
-        if (listener == null) {
-            throw new IllegalArgumentException("listener must not be null");
-        }
-
-        // List is self-synchronized copy-on-write.
-        mDisplayTransactionListeners.add(listener);
-    }
-
-    /**
-     * Unregisters a display transaction listener to provide the client a chance to
-     * update its surfaces within the same transaction as any display layout updates.
-     *
-     * @param listener The listener to unregister.
-     */
-    public void unregisterDisplayTransactionListener(DisplayTransactionListener listener) {
-        if (listener == null) {
-            throw new IllegalArgumentException("listener must not be null");
-        }
-
-        // List is self-synchronized copy-on-write.
-        mDisplayTransactionListeners.remove(listener);
-    }
-
-    /**
-     * Overrides the display information of a particular logical display.
-     * This is used by the window manager to control the size and characteristics
-     * of the default display.  It is expected to apply the requested change
-     * to the display information synchronously so that applications will immediately
-     * observe the new state.
-     *
-     * NOTE: This method must be the only entry point by which the window manager
-     * influences the logical configuration of displays.
-     *
-     * @param displayId The logical display id.
-     * @param info The new data to be stored.
-     */
-    public void setDisplayInfoOverrideFromWindowManager(
-            int displayId, DisplayInfo info) {
-        synchronized (mSyncRoot) {
-            LogicalDisplay display = mLogicalDisplays.get(displayId);
-            if (display != null) {
-                if (display.setDisplayInfoOverrideFromWindowManagerLocked(info)) {
-                    sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_CHANGED);
-                    scheduleTraversalLocked(false);
-                }
-            }
-        }
-    }
-
-    /**
-     * Called by the window manager to perform traversals while holding a
-     * surface flinger transaction.
-     */
-    public void performTraversalInTransactionFromWindowManager() {
-        synchronized (mSyncRoot) {
-            if (!mPendingTraversal) {
-                return;
-            }
-            mPendingTraversal = false;
-
-            performTraversalInTransactionLocked();
-        }
-
-        // List is self-synchronized copy-on-write.
-        for (DisplayTransactionListener listener : mDisplayTransactionListeners) {
-            listener.onDisplayTransaction();
-        }
-    }
-
-    /**
-     * Called by the power manager to blank all displays.
-     */
-    public void blankAllDisplaysFromPowerManager() {
-        synchronized (mSyncRoot) {
-            if (mAllDisplayBlankStateFromPowerManager != DISPLAY_BLANK_STATE_BLANKED) {
-                mAllDisplayBlankStateFromPowerManager = DISPLAY_BLANK_STATE_BLANKED;
-                updateAllDisplayBlankingLocked();
-                scheduleTraversalLocked(false);
-            }
-        }
-    }
-
-    /**
-     * Called by the power manager to unblank all displays.
-     */
-    public void unblankAllDisplaysFromPowerManager() {
-        synchronized (mSyncRoot) {
-            if (mAllDisplayBlankStateFromPowerManager != DISPLAY_BLANK_STATE_UNBLANKED) {
-                mAllDisplayBlankStateFromPowerManager = DISPLAY_BLANK_STATE_UNBLANKED;
-                updateAllDisplayBlankingLocked();
-                scheduleTraversalLocked(false);
-            }
-        }
-    }
-
-    /**
-     * Returns information about the specified logical display.
-     *
-     * @param displayId The logical display id.
-     * @return The logical display info, or null if the display does not exist.  The
-     * returned object must be treated as immutable.
-     */
-    @Override // Binder call
-    public DisplayInfo getDisplayInfo(int displayId) {
-        final int callingUid = Binder.getCallingUid();
-        final long token = Binder.clearCallingIdentity();
-        try {
-            synchronized (mSyncRoot) {
-                LogicalDisplay display = mLogicalDisplays.get(displayId);
-                if (display != null) {
-                    DisplayInfo info = display.getDisplayInfoLocked();
-                    if (info.hasAccess(callingUid)) {
-                        return info;
-                    }
-                }
-                return null;
-            }
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
-    }
-
-    /**
-     * Returns the list of all display ids.
-     */
-    @Override // Binder call
-    public int[] getDisplayIds() {
-        final int callingUid = Binder.getCallingUid();
-        final long token = Binder.clearCallingIdentity();
-        try {
-            synchronized (mSyncRoot) {
-                final int count = mLogicalDisplays.size();
-                int[] displayIds = new int[count];
-                int n = 0;
-                for (int i = 0; i < count; i++) {
-                    LogicalDisplay display = mLogicalDisplays.valueAt(i);
-                    DisplayInfo info = display.getDisplayInfoLocked();
-                    if (info.hasAccess(callingUid)) {
-                        displayIds[n++] = mLogicalDisplays.keyAt(i);
-                    }
-                }
-                if (n != count) {
-                    displayIds = Arrays.copyOfRange(displayIds, 0, n);
-                }
-                return displayIds;
-            }
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
-    }
-
-    @Override // Binder call
-    public void registerCallback(IDisplayManagerCallback callback) {
-        if (callback == null) {
-            throw new IllegalArgumentException("listener must not be null");
-        }
-
-        synchronized (mSyncRoot) {
-            int callingPid = Binder.getCallingPid();
-            if (mCallbacks.get(callingPid) != null) {
-                throw new SecurityException("The calling process has already "
-                        + "registered an IDisplayManagerCallback.");
-            }
-
-            CallbackRecord record = new CallbackRecord(callingPid, callback);
-            try {
-                IBinder binder = callback.asBinder();
-                binder.linkToDeath(record, 0);
-            } catch (RemoteException ex) {
-                // give up
-                throw new RuntimeException(ex);
-            }
-
-            mCallbacks.put(callingPid, record);
-        }
-    }
-
-    private void onCallbackDied(CallbackRecord record) {
-        synchronized (mSyncRoot) {
-            mCallbacks.remove(record.mPid);
-            stopWifiDisplayScanLocked(record);
-        }
-    }
-
-    @Override // Binder call
-    public void startWifiDisplayScan() {
-        mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY,
-                "Permission required to start wifi display scans");
-
-        final int callingPid = Binder.getCallingPid();
-        final long token = Binder.clearCallingIdentity();
-        try {
-            synchronized (mSyncRoot) {
-                CallbackRecord record = mCallbacks.get(callingPid);
-                if (record == null) {
-                    throw new IllegalStateException("The calling process has not "
-                            + "registered an IDisplayManagerCallback.");
-                }
-                startWifiDisplayScanLocked(record);
-            }
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
-    }
-
-    private void startWifiDisplayScanLocked(CallbackRecord record) {
-        if (!record.mWifiDisplayScanRequested) {
-            record.mWifiDisplayScanRequested = true;
-            if (mWifiDisplayScanRequestCount++ == 0) {
-                if (mWifiDisplayAdapter != null) {
-                    mWifiDisplayAdapter.requestStartScanLocked();
-                }
-            }
-        }
-    }
-
-    @Override // Binder call
-    public void stopWifiDisplayScan() {
-        mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY,
-                "Permission required to stop wifi display scans");
-
-        final int callingPid = Binder.getCallingPid();
-        final long token = Binder.clearCallingIdentity();
-        try {
-            synchronized (mSyncRoot) {
-                CallbackRecord record = mCallbacks.get(callingPid);
-                if (record == null) {
-                    throw new IllegalStateException("The calling process has not "
-                            + "registered an IDisplayManagerCallback.");
-                }
-                stopWifiDisplayScanLocked(record);
-            }
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
-    }
-
-    private void stopWifiDisplayScanLocked(CallbackRecord record) {
-        if (record.mWifiDisplayScanRequested) {
-            record.mWifiDisplayScanRequested = false;
-            if (--mWifiDisplayScanRequestCount == 0) {
-                if (mWifiDisplayAdapter != null) {
-                    mWifiDisplayAdapter.requestStopScanLocked();
-                }
-            } else if (mWifiDisplayScanRequestCount < 0) {
-                Log.wtf(TAG, "mWifiDisplayScanRequestCount became negative: "
-                        + mWifiDisplayScanRequestCount);
-                mWifiDisplayScanRequestCount = 0;
-            }
-        }
-    }
-
-    @Override // Binder call
-    public void connectWifiDisplay(String address) {
-        if (address == null) {
-            throw new IllegalArgumentException("address must not be null");
-        }
-        mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY,
-                "Permission required to connect to a wifi display");
-
-        final long token = Binder.clearCallingIdentity();
-        try {
-            synchronized (mSyncRoot) {
-                if (mWifiDisplayAdapter != null) {
-                    mWifiDisplayAdapter.requestConnectLocked(address);
-                }
-            }
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
-    }
-
-    @Override
-    public void pauseWifiDisplay() {
-        mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY,
-                "Permission required to pause a wifi display session");
-
-        final long token = Binder.clearCallingIdentity();
-        try {
-            synchronized (mSyncRoot) {
-                if (mWifiDisplayAdapter != null) {
-                    mWifiDisplayAdapter.requestPauseLocked();
-                }
-            }
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
-    }
-
-    @Override
-    public void resumeWifiDisplay() {
-        mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY,
-                "Permission required to resume a wifi display session");
-
-        final long token = Binder.clearCallingIdentity();
-        try {
-            synchronized (mSyncRoot) {
-                if (mWifiDisplayAdapter != null) {
-                    mWifiDisplayAdapter.requestResumeLocked();
-                }
-            }
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
-    }
-
-    @Override // Binder call
-    public void disconnectWifiDisplay() {
-        // This request does not require special permissions.
-        // Any app can request disconnection from the currently active wifi display.
-        // This exception should no longer be needed once wifi display control moves
-        // to the media router service.
-
-        final long token = Binder.clearCallingIdentity();
-        try {
-            synchronized (mSyncRoot) {
-                if (mWifiDisplayAdapter != null) {
-                    mWifiDisplayAdapter.requestDisconnectLocked();
-                }
-            }
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
-    }
-
-    @Override // Binder call
-    public void renameWifiDisplay(String address, String alias) {
-        if (address == null) {
-            throw new IllegalArgumentException("address must not be null");
-        }
-        mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY,
-                "Permission required to rename to a wifi display");
-
-        final long token = Binder.clearCallingIdentity();
-        try {
-            synchronized (mSyncRoot) {
-                if (mWifiDisplayAdapter != null) {
-                    mWifiDisplayAdapter.requestRenameLocked(address, alias);
-                }
-            }
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
-    }
-
-    @Override // Binder call
-    public void forgetWifiDisplay(String address) {
-        if (address == null) {
-            throw new IllegalArgumentException("address must not be null");
-        }
-        mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY,
-                "Permission required to forget to a wifi display");
-
-        final long token = Binder.clearCallingIdentity();
-        try {
-            synchronized (mSyncRoot) {
-                if (mWifiDisplayAdapter != null) {
-                    mWifiDisplayAdapter.requestForgetLocked(address);
-                }
-            }
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
-    }
-
-    @Override // Binder call
-    public WifiDisplayStatus getWifiDisplayStatus() {
-        // This request does not require special permissions.
-        // Any app can get information about available wifi displays.
-
-        final long token = Binder.clearCallingIdentity();
-        try {
-            synchronized (mSyncRoot) {
-                if (mWifiDisplayAdapter != null) {
-                    return mWifiDisplayAdapter.getWifiDisplayStatusLocked();
-                }
-                return new WifiDisplayStatus();
-            }
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
-    }
-
-    @Override // Binder call
-    public int createVirtualDisplay(IBinder appToken, String packageName,
-            String name, int width, int height, int densityDpi, Surface surface, int flags) {
-        final int callingUid = Binder.getCallingUid();
-        if (!validatePackageName(callingUid, packageName)) {
-            throw new SecurityException("packageName must match the calling uid");
-        }
-        if (appToken == null) {
-            throw new IllegalArgumentException("appToken must not be null");
-        }
-        if (TextUtils.isEmpty(name)) {
-            throw new IllegalArgumentException("name must be non-null and non-empty");
-        }
-        if (width <= 0 || height <= 0 || densityDpi <= 0) {
-            throw new IllegalArgumentException("width, height, and densityDpi must be "
-                    + "greater than 0");
-        }
-        if (surface == null) {
-            throw new IllegalArgumentException("surface must not be null");
-        }
-        if ((flags & DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC) != 0) {
-            if (mContext.checkCallingPermission(android.Manifest.permission.CAPTURE_VIDEO_OUTPUT)
-                    != PackageManager.PERMISSION_GRANTED
-                    && mContext.checkCallingPermission(
-                            android.Manifest.permission.CAPTURE_SECURE_VIDEO_OUTPUT)
-                            != PackageManager.PERMISSION_GRANTED) {
-                throw new SecurityException("Requires CAPTURE_VIDEO_OUTPUT or "
-                        + "CAPTURE_SECURE_VIDEO_OUTPUT permission to create a "
-                        + "public virtual display.");
-            }
-        }
-        if ((flags & DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE) != 0) {
-            if (mContext.checkCallingPermission(
-                    android.Manifest.permission.CAPTURE_SECURE_VIDEO_OUTPUT)
-                    != PackageManager.PERMISSION_GRANTED) {
-                throw new SecurityException("Requires CAPTURE_SECURE_VIDEO_OUTPUT "
-                        + "to create a secure virtual display.");
-            }
-        }
-
-        final long token = Binder.clearCallingIdentity();
-        try {
-            synchronized (mSyncRoot) {
-                if (mVirtualDisplayAdapter == null) {
-                    Slog.w(TAG, "Rejecting request to create private virtual display "
-                            + "because the virtual display adapter is not available.");
-                    return -1;
-                }
-
-                DisplayDevice device = mVirtualDisplayAdapter.createVirtualDisplayLocked(
-                        appToken, callingUid, packageName, name, width, height, densityDpi,
-                        surface, flags);
-                if (device == null) {
-                    return -1;
-                }
-
-                handleDisplayDeviceAddedLocked(device);
-                LogicalDisplay display = findLogicalDisplayForDeviceLocked(device);
-                if (display != null) {
-                    return display.getDisplayIdLocked();
-                }
-
-                // Something weird happened and the logical display was not created.
-                Slog.w(TAG, "Rejecting request to create virtual display "
-                        + "because the logical display was not created.");
-                mVirtualDisplayAdapter.releaseVirtualDisplayLocked(appToken);
-                handleDisplayDeviceRemovedLocked(device);
-            }
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
-        return -1;
-    }
-
-    @Override // Binder call
-    public void releaseVirtualDisplay(IBinder appToken) {
-        final long token = Binder.clearCallingIdentity();
-        try {
-            synchronized (mSyncRoot) {
-                if (mVirtualDisplayAdapter == null) {
-                    return;
-                }
-
-                DisplayDevice device =
-                        mVirtualDisplayAdapter.releaseVirtualDisplayLocked(appToken);
-                if (device != null) {
-                    handleDisplayDeviceRemovedLocked(device);
-                }
-            }
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
-    }
-
-    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;
-    }
-
-    private void registerDefaultDisplayAdapter() {
-        // Register default display adapter.
-        synchronized (mSyncRoot) {
-            if (mHeadless) {
-                registerDisplayAdapterLocked(new HeadlessDisplayAdapter(
-                        mSyncRoot, mContext, mHandler, mDisplayAdapterListener));
-            } else {
-                registerDisplayAdapterLocked(new LocalDisplayAdapter(
-                        mSyncRoot, mContext, mHandler, mDisplayAdapterListener));
-            }
-        }
-    }
-
-    private void registerAdditionalDisplayAdapters() {
-        synchronized (mSyncRoot) {
-            if (shouldRegisterNonEssentialDisplayAdaptersLocked()) {
-                registerOverlayDisplayAdapterLocked();
-                registerWifiDisplayAdapterLocked();
-                registerVirtualDisplayAdapterLocked();
-            }
-        }
-    }
-
-    private void registerOverlayDisplayAdapterLocked() {
-        registerDisplayAdapterLocked(new OverlayDisplayAdapter(
-                mSyncRoot, mContext, mHandler, mDisplayAdapterListener, mUiHandler));
-    }
-
-    private void registerWifiDisplayAdapterLocked() {
-        if (mContext.getResources().getBoolean(
-                com.android.internal.R.bool.config_enableWifiDisplay)
-                || SystemProperties.getInt(FORCE_WIFI_DISPLAY_ENABLE, -1) == 1) {
-            mWifiDisplayAdapter = new WifiDisplayAdapter(
-                    mSyncRoot, mContext, mHandler, mDisplayAdapterListener,
-                    mPersistentDataStore);
-            registerDisplayAdapterLocked(mWifiDisplayAdapter);
-        }
-    }
-
-    private void registerVirtualDisplayAdapterLocked() {
-        mVirtualDisplayAdapter = new VirtualDisplayAdapter(
-                mSyncRoot, mContext, mHandler, mDisplayAdapterListener);
-        registerDisplayAdapterLocked(mVirtualDisplayAdapter);
-    }
-
-    private boolean shouldRegisterNonEssentialDisplayAdaptersLocked() {
-        // In safe mode, we disable non-essential display adapters to give the user
-        // an opportunity to fix broken settings or other problems that might affect
-        // system stability.
-        // In only-core mode, we disable non-essential display adapters to minimize
-        // the number of dependencies that are started while in this mode and to
-        // prevent problems that might occur due to the device being encrypted.
-        return !mSafeMode && !mOnlyCore;
-    }
-
-    private void registerDisplayAdapterLocked(DisplayAdapter adapter) {
-        mDisplayAdapters.add(adapter);
-        adapter.registerLocked();
-    }
-
-    private void handleDisplayDeviceAdded(DisplayDevice device) {
-        synchronized (mSyncRoot) {
-            handleDisplayDeviceAddedLocked(device);
-        }
-    }
-
-    private void handleDisplayDeviceAddedLocked(DisplayDevice device) {
-        if (mDisplayDevices.contains(device)) {
-            Slog.w(TAG, "Attempted to add already added display device: "
-                    + device.getDisplayDeviceInfoLocked());
-            return;
-        }
-
-        Slog.i(TAG, "Display device added: " + device.getDisplayDeviceInfoLocked());
-
-        mDisplayDevices.add(device);
-        addLogicalDisplayLocked(device);
-        updateDisplayBlankingLocked(device);
-        scheduleTraversalLocked(false);
-    }
-
-    private void handleDisplayDeviceChanged(DisplayDevice device) {
-        synchronized (mSyncRoot) {
-            if (!mDisplayDevices.contains(device)) {
-                Slog.w(TAG, "Attempted to change non-existent display device: "
-                        + device.getDisplayDeviceInfoLocked());
-                return;
-            }
-
-            Slog.i(TAG, "Display device changed: " + device.getDisplayDeviceInfoLocked());
-
-            device.applyPendingDisplayDeviceInfoChangesLocked();
-            if (updateLogicalDisplaysLocked()) {
-                scheduleTraversalLocked(false);
-            }
-        }
-    }
-
-    private void handleDisplayDeviceRemoved(DisplayDevice device) {
-        synchronized (mSyncRoot) {
-            handleDisplayDeviceRemovedLocked(device);
-        }
-    }
-    private void handleDisplayDeviceRemovedLocked(DisplayDevice device) {
-        if (!mDisplayDevices.remove(device)) {
-            Slog.w(TAG, "Attempted to remove non-existent display device: "
-                    + device.getDisplayDeviceInfoLocked());
-            return;
-        }
-
-        Slog.i(TAG, "Display device removed: " + device.getDisplayDeviceInfoLocked());
-
-        updateLogicalDisplaysLocked();
-        scheduleTraversalLocked(false);
-    }
-
-    private void updateAllDisplayBlankingLocked() {
-        final int count = mDisplayDevices.size();
-        for (int i = 0; i < count; i++) {
-            DisplayDevice device = mDisplayDevices.get(i);
-            updateDisplayBlankingLocked(device);
-        }
-    }
-
-    private void updateDisplayBlankingLocked(DisplayDevice device) {
-        // Blank or unblank the display immediately to match the state requested
-        // by the power manager (if known).
-        DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
-        if ((info.flags & DisplayDeviceInfo.FLAG_NEVER_BLANK) == 0) {
-            switch (mAllDisplayBlankStateFromPowerManager) {
-                case DISPLAY_BLANK_STATE_BLANKED:
-                    device.blankLocked();
-                    break;
-                case DISPLAY_BLANK_STATE_UNBLANKED:
-                    device.unblankLocked();
-                    break;
-            }
-        }
-    }
-
-    // Adds a new logical display based on the given display device.
-    // Sends notifications if needed.
-    private void addLogicalDisplayLocked(DisplayDevice device) {
-        DisplayDeviceInfo deviceInfo = device.getDisplayDeviceInfoLocked();
-        boolean isDefault = (deviceInfo.flags
-                & DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY) != 0;
-        if (isDefault && mLogicalDisplays.get(Display.DEFAULT_DISPLAY) != null) {
-            Slog.w(TAG, "Ignoring attempt to add a second default display: " + deviceInfo);
-            isDefault = false;
-        }
-
-        if (!isDefault && mSingleDisplayDemoMode) {
-            Slog.i(TAG, "Not creating a logical display for a secondary display "
-                    + " because single display demo mode is enabled: " + deviceInfo);
-            return;
-        }
-
-        final int displayId = assignDisplayIdLocked(isDefault);
-        final int layerStack = assignLayerStackLocked(displayId);
-
-        LogicalDisplay display = new LogicalDisplay(displayId, layerStack, device);
-        display.updateLocked(mDisplayDevices);
-        if (!display.isValidLocked()) {
-            // This should never happen currently.
-            Slog.w(TAG, "Ignoring display device because the logical display "
-                    + "created from it was not considered valid: " + deviceInfo);
-            return;
-        }
-
-        mLogicalDisplays.put(displayId, display);
-
-        // Wake up waitForDefaultDisplay.
-        if (isDefault) {
-            mSyncRoot.notifyAll();
-        }
-
-        sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_ADDED);
-    }
-
-    private int assignDisplayIdLocked(boolean isDefault) {
-        return isDefault ? Display.DEFAULT_DISPLAY : mNextNonDefaultDisplayId++;
-    }
-
-    private int assignLayerStackLocked(int displayId) {
-        // Currently layer stacks and display ids are the same.
-        // This need not be the case.
-        return displayId;
-    }
-
-    // Updates all existing logical displays given the current set of display devices.
-    // Removes invalid logical displays.
-    // Sends notifications if needed.
-    private boolean updateLogicalDisplaysLocked() {
-        boolean changed = false;
-        for (int i = mLogicalDisplays.size(); i-- > 0; ) {
-            final int displayId = mLogicalDisplays.keyAt(i);
-            LogicalDisplay display = mLogicalDisplays.valueAt(i);
-
-            mTempDisplayInfo.copyFrom(display.getDisplayInfoLocked());
-            display.updateLocked(mDisplayDevices);
-            if (!display.isValidLocked()) {
-                mLogicalDisplays.removeAt(i);
-                sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_REMOVED);
-                changed = true;
-            } else if (!mTempDisplayInfo.equals(display.getDisplayInfoLocked())) {
-                sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_CHANGED);
-                changed = true;
-            }
-        }
-        return changed;
-    }
-
-    private void performTraversalInTransactionLocked() {
-        // Clear all viewports before configuring displays so that we can keep
-        // track of which ones we have configured.
-        clearViewportsLocked();
-
-        // Configure each display device.
-        final int count = mDisplayDevices.size();
-        for (int i = 0; i < count; i++) {
-            DisplayDevice device = mDisplayDevices.get(i);
-            configureDisplayInTransactionLocked(device);
-            device.performTraversalInTransactionLocked();
-        }
-
-        // Tell the input system about these new viewports.
-        if (mInputManagerFuncs != null) {
-            mHandler.sendEmptyMessage(MSG_UPDATE_VIEWPORT);
-        }
-    }
-
-    /**
-     * Tells the display manager whether there is interesting unique content on the
-     * specified logical display.  This is used to control automatic mirroring.
-     * <p>
-     * If the display has unique content, then the display manager arranges for it
-     * to be presented on a physical display if appropriate.  Otherwise, the display manager
-     * may choose to make the physical display mirror some other logical display.
-     * </p>
-     *
-     * @param displayId The logical display id to update.
-     * @param hasContent True if the logical display has content.
-     * @param inTraversal True if called from WindowManagerService during a window traversal prior
-     * to call to performTraversalInTransactionFromWindowManager.
-     */
-    public void setDisplayHasContent(int displayId, boolean hasContent, boolean inTraversal) {
-        synchronized (mSyncRoot) {
-            LogicalDisplay display = mLogicalDisplays.get(displayId);
-            if (display != null && display.hasContentLocked() != hasContent) {
-                if (DEBUG) {
-                    Slog.d(TAG, "Display " + displayId + " hasContent flag changed: "
-                            + "hasContent=" + hasContent + ", inTraversal=" + inTraversal);
-                }
-
-                display.setHasContentLocked(hasContent);
-                scheduleTraversalLocked(inTraversal);
-            }
-        }
-    }
-
-    private void clearViewportsLocked() {
-        mDefaultViewport.valid = false;
-        mExternalTouchViewport.valid = false;
-    }
-
-    private void configureDisplayInTransactionLocked(DisplayDevice device) {
-        DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
-        boolean isPrivate = (info.flags & DisplayDeviceInfo.FLAG_PRIVATE) != 0;
-
-        // Find the logical display that the display device is showing.
-        // Private displays never mirror other displays.
-        LogicalDisplay display = findLogicalDisplayForDeviceLocked(device);
-        if (!isPrivate) {
-            if (display != null && !display.hasContentLocked()) {
-                // If the display does not have any content of its own, then
-                // automatically mirror the default logical display contents.
-                display = null;
-            }
-            if (display == null) {
-                display = mLogicalDisplays.get(Display.DEFAULT_DISPLAY);
-            }
-        }
-
-        // Apply the logical display configuration to the display device.
-        if (display == null) {
-            // TODO: no logical display for the device, blank it
-            Slog.w(TAG, "Missing logical display to use for physical display device: "
-                    + device.getDisplayDeviceInfoLocked());
-            return;
-        }
-        boolean isBlanked = (mAllDisplayBlankStateFromPowerManager == DISPLAY_BLANK_STATE_BLANKED)
-                && (info.flags & DisplayDeviceInfo.FLAG_NEVER_BLANK) == 0;
-        display.configureDisplayInTransactionLocked(device, isBlanked);
-
-        // Update the viewports if needed.
-        if (!mDefaultViewport.valid
-                && (info.flags & DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY) != 0) {
-            setViewportLocked(mDefaultViewport, display, device);
-        }
-        if (!mExternalTouchViewport.valid
-                && info.touch == DisplayDeviceInfo.TOUCH_EXTERNAL) {
-            setViewportLocked(mExternalTouchViewport, display, device);
-        }
-    }
-
-    private static void setViewportLocked(DisplayViewport viewport,
-            LogicalDisplay display, DisplayDevice device) {
-        viewport.valid = true;
-        viewport.displayId = display.getDisplayIdLocked();
-        device.populateViewportLocked(viewport);
-    }
-
-    private LogicalDisplay findLogicalDisplayForDeviceLocked(DisplayDevice device) {
-        final int count = mLogicalDisplays.size();
-        for (int i = 0; i < count; i++) {
-            LogicalDisplay display = mLogicalDisplays.valueAt(i);
-            if (display.getPrimaryDisplayDeviceLocked() == device) {
-                return display;
-            }
-        }
-        return null;
-    }
-
-    private void sendDisplayEventLocked(int displayId, int event) {
-        Message msg = mHandler.obtainMessage(MSG_DELIVER_DISPLAY_EVENT, displayId, event);
-        mHandler.sendMessage(msg);
-    }
-
-    // Requests that performTraversalsInTransactionFromWindowManager be called at a
-    // later time to apply changes to surfaces and displays.
-    private void scheduleTraversalLocked(boolean inTraversal) {
-        if (!mPendingTraversal && mWindowManagerFuncs != null) {
-            mPendingTraversal = true;
-            if (!inTraversal) {
-                mHandler.sendEmptyMessage(MSG_REQUEST_TRAVERSAL);
-            }
-        }
-    }
-
-    // Runs on Handler thread.
-    // Delivers display event notifications to callbacks.
-    private void deliverDisplayEvent(int displayId, int event) {
-        if (DEBUG) {
-            Slog.d(TAG, "Delivering display event: displayId="
-                    + displayId + ", event=" + event);
-        }
-
-        // Grab the lock and copy the callbacks.
-        final int count;
-        synchronized (mSyncRoot) {
-            count = mCallbacks.size();
-            mTempCallbacks.clear();
-            for (int i = 0; i < count; i++) {
-                mTempCallbacks.add(mCallbacks.valueAt(i));
-            }
-        }
-
-        // After releasing the lock, send the notifications out.
-        for (int i = 0; i < count; i++) {
-            mTempCallbacks.get(i).notifyDisplayEventAsync(displayId, event);
-        }
-        mTempCallbacks.clear();
-    }
-
-    @Override // Binder call
-    public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
-        if (mContext == null
-                || mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP)
-                        != PackageManager.PERMISSION_GRANTED) {
-            pw.println("Permission Denial: can't dump DisplayManager from from pid="
-                    + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
-            return;
-        }
-
-        pw.println("DISPLAY MANAGER (dumpsys display)");
-
-        synchronized (mSyncRoot) {
-            pw.println("  mHeadless=" + mHeadless);
-            pw.println("  mOnlyCode=" + mOnlyCore);
-            pw.println("  mSafeMode=" + mSafeMode);
-            pw.println("  mPendingTraversal=" + mPendingTraversal);
-            pw.println("  mAllDisplayBlankStateFromPowerManager="
-                    + mAllDisplayBlankStateFromPowerManager);
-            pw.println("  mNextNonDefaultDisplayId=" + mNextNonDefaultDisplayId);
-            pw.println("  mDefaultViewport=" + mDefaultViewport);
-            pw.println("  mExternalTouchViewport=" + mExternalTouchViewport);
-            pw.println("  mSingleDisplayDemoMode=" + mSingleDisplayDemoMode);
-            pw.println("  mWifiDisplayScanRequestCount=" + mWifiDisplayScanRequestCount);
-
-            IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "    ");
-            ipw.increaseIndent();
-
-            pw.println();
-            pw.println("Display Adapters: size=" + mDisplayAdapters.size());
-            for (DisplayAdapter adapter : mDisplayAdapters) {
-                pw.println("  " + adapter.getName());
-                adapter.dumpLocked(ipw);
-            }
-
-            pw.println();
-            pw.println("Display Devices: size=" + mDisplayDevices.size());
-            for (DisplayDevice device : mDisplayDevices) {
-                pw.println("  " + device.getDisplayDeviceInfoLocked());
-                device.dumpLocked(ipw);
-            }
-
-            final int logicalDisplayCount = mLogicalDisplays.size();
-            pw.println();
-            pw.println("Logical Displays: size=" + logicalDisplayCount);
-            for (int i = 0; i < logicalDisplayCount; i++) {
-                int displayId = mLogicalDisplays.keyAt(i);
-                LogicalDisplay display = mLogicalDisplays.valueAt(i);
-                pw.println("  Display " + displayId + ":");
-                display.dumpLocked(ipw);
-            }
-
-            final int callbackCount = mCallbacks.size();
-            pw.println();
-            pw.println("Callbacks: size=" + callbackCount);
-            for (int i = 0; i < callbackCount; i++) {
-                CallbackRecord callback = mCallbacks.valueAt(i);
-                pw.println("  " + i + ": mPid=" + callback.mPid
-                        + ", mWifiDisplayScanRequested=" + callback.mWifiDisplayScanRequested);
-            }
-        }
-    }
-
-    /**
-     * This is the object that everything in the display manager locks on.
-     * We make it an inner class within the {@link DisplayManagerService} to so that it is
-     * clear that the object belongs to the display manager service and that it is
-     * a unique object with a special purpose.
-     */
-    public static final class SyncRoot {
-    }
-
-    /**
-     * Private interface to the window manager.
-     */
-    public interface WindowManagerFuncs {
-        /**
-         * Request that the window manager call
-         * {@link #performTraversalInTransactionFromWindowManager} within a surface
-         * transaction at a later time.
-         */
-        void requestTraversal();
-    }
-
-    /**
-     * Private interface to the input manager.
-     */
-    public interface InputManagerFuncs {
-        /**
-         * Sets information about the displays as needed by the input system.
-         * The input system should copy this information if required.
-         */
-        void setDisplayViewports(DisplayViewport defaultViewport,
-                DisplayViewport externalTouchViewport);
-    }
-
-    private final class DisplayManagerHandler extends Handler {
-        public DisplayManagerHandler(Looper looper) {
-            super(looper, null, true /*async*/);
-        }
-
-        @Override
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-                case MSG_REGISTER_DEFAULT_DISPLAY_ADAPTER:
-                    registerDefaultDisplayAdapter();
-                    break;
-
-                case MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS:
-                    registerAdditionalDisplayAdapters();
-                    break;
-
-                case MSG_DELIVER_DISPLAY_EVENT:
-                    deliverDisplayEvent(msg.arg1, msg.arg2);
-                    break;
-
-                case MSG_REQUEST_TRAVERSAL:
-                    mWindowManagerFuncs.requestTraversal();
-                    break;
-
-                case MSG_UPDATE_VIEWPORT: {
-                    synchronized (mSyncRoot) {
-                        mTempDefaultViewport.copyFrom(mDefaultViewport);
-                        mTempExternalTouchViewport.copyFrom(mExternalTouchViewport);
-                    }
-                    mInputManagerFuncs.setDisplayViewports(
-                            mTempDefaultViewport, mTempExternalTouchViewport);
-                    break;
-                }
-            }
-        }
-    }
-
-    private final class DisplayAdapterListener implements DisplayAdapter.Listener {
-        @Override
-        public void onDisplayDeviceEvent(DisplayDevice device, int event) {
-            switch (event) {
-                case DisplayAdapter.DISPLAY_DEVICE_EVENT_ADDED:
-                    handleDisplayDeviceAdded(device);
-                    break;
-
-                case DisplayAdapter.DISPLAY_DEVICE_EVENT_CHANGED:
-                    handleDisplayDeviceChanged(device);
-                    break;
-
-                case DisplayAdapter.DISPLAY_DEVICE_EVENT_REMOVED:
-                    handleDisplayDeviceRemoved(device);
-                    break;
-            }
-        }
-
-        @Override
-        public void onTraversalRequested() {
-            synchronized (mSyncRoot) {
-                scheduleTraversalLocked(false);
-            }
-        }
-    }
-
-    private final class CallbackRecord implements DeathRecipient {
-        public final int mPid;
-        private final IDisplayManagerCallback mCallback;
-
-        public boolean mWifiDisplayScanRequested;
-
-        public CallbackRecord(int pid, IDisplayManagerCallback callback) {
-            mPid = pid;
-            mCallback = callback;
-        }
-
-        @Override
-        public void binderDied() {
-            if (DEBUG) {
-                Slog.d(TAG, "Display listener for pid " + mPid + " died.");
-            }
-            onCallbackDied(this);
-        }
-
-        public void notifyDisplayEventAsync(int displayId, int event) {
-            try {
-                mCallback.onDisplayEvent(displayId, event);
-            } catch (RemoteException ex) {
-                Slog.w(TAG, "Failed to notify process "
-                        + mPid + " that displays changed, assuming it died.", ex);
-                binderDied();
-            }
-        }
-    }
-}
diff --git a/services/java/com/android/server/display/DisplayTransactionListener.java b/services/java/com/android/server/display/DisplayTransactionListener.java
deleted file mode 100644
index 34eb8f9..0000000
--- a/services/java/com/android/server/display/DisplayTransactionListener.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.display;
-
-/**
- * Called within a Surface transaction whenever the size or orientation of a
- * display may have changed.  Provides an opportunity for the client to
- * update the position of its surfaces as part of the same transaction.
- */
-public interface DisplayTransactionListener {
-    void onDisplayTransaction();
-}
diff --git a/services/java/com/android/server/display/HeadlessDisplayAdapter.java b/services/java/com/android/server/display/HeadlessDisplayAdapter.java
deleted file mode 100644
index 7a104d7..0000000
--- a/services/java/com/android/server/display/HeadlessDisplayAdapter.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.display;
-
-import android.content.Context;
-import android.os.Handler;
-import android.util.DisplayMetrics;
-import android.view.Display;
-
-/**
- * Provides a fake default display for headless systems.
- * <p>
- * Display adapters are guarded by the {@link DisplayManagerService.SyncRoot} lock.
- * </p>
- */
-final class HeadlessDisplayAdapter extends DisplayAdapter {
-    private static final String TAG = "HeadlessDisplayAdapter";
-
-    // Called with SyncRoot lock held.
-    public HeadlessDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
-            Context context, Handler handler, Listener listener) {
-        super(syncRoot, context, handler, listener, TAG);
-    }
-
-    @Override
-    public void registerLocked() {
-        super.registerLocked();
-        sendDisplayDeviceEventLocked(new HeadlessDisplayDevice(), DISPLAY_DEVICE_EVENT_ADDED);
-    }
-
-    private final class HeadlessDisplayDevice extends DisplayDevice {
-        private DisplayDeviceInfo mInfo;
-
-        public HeadlessDisplayDevice() {
-            super(HeadlessDisplayAdapter.this, null);
-        }
-
-        @Override
-        public DisplayDeviceInfo getDisplayDeviceInfoLocked() {
-            if (mInfo == null) {
-                mInfo = new DisplayDeviceInfo();
-                mInfo.name = getContext().getResources().getString(
-                        com.android.internal.R.string.display_manager_built_in_display_name);
-                mInfo.width = 640;
-                mInfo.height = 480;
-                mInfo.refreshRate = 60;
-                mInfo.densityDpi = DisplayMetrics.DENSITY_DEFAULT;
-                mInfo.xDpi = 160;
-                mInfo.yDpi = 160;
-                mInfo.flags = DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY
-                        | DisplayDeviceInfo.FLAG_SECURE
-                        | DisplayDeviceInfo.FLAG_SUPPORTS_PROTECTED_BUFFERS;
-                mInfo.type = Display.TYPE_BUILT_IN;
-                mInfo.touch = DisplayDeviceInfo.TOUCH_NONE;
-            }
-            return mInfo;
-        }
-    }
-}
diff --git a/services/java/com/android/server/dreams/DreamManagerService.java b/services/java/com/android/server/dreams/DreamManagerService.java
deleted file mode 100644
index b6e7781..0000000
--- a/services/java/com/android/server/dreams/DreamManagerService.java
+++ /dev/null
@@ -1,425 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.dreams;
-
-import com.android.internal.util.DumpUtils;
-
-import android.app.ActivityManager;
-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.PackageManager.NameNotFoundException;
-import android.os.Binder;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.PowerManager;
-import android.os.SystemClock;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.service.dreams.IDreamManager;
-import android.util.Slog;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.List;
-
-import libcore.util.Objects;
-
-/**
- * Service api for managing dreams.
- *
- * @hide
- */
-public final class DreamManagerService extends IDreamManager.Stub {
-    private static final boolean DEBUG = false;
-    private static final String TAG = "DreamManagerService";
-
-    private final Object mLock = new Object();
-
-    private final Context mContext;
-    private final DreamHandler mHandler;
-    private final DreamController mController;
-    private final PowerManager mPowerManager;
-
-    private Binder mCurrentDreamToken;
-    private ComponentName mCurrentDreamName;
-    private int mCurrentDreamUserId;
-    private boolean mCurrentDreamIsTest;
-
-    public DreamManagerService(Context context, Handler mainHandler) {
-        mContext = context;
-        mHandler = new DreamHandler(mainHandler.getLooper());
-        mController = new DreamController(context, mHandler, mControllerListener);
-
-        mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
-    }
-
-    public void systemRunning() {
-        mContext.registerReceiver(new BroadcastReceiver() {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                synchronized (mLock) {
-                    stopDreamLocked();
-                }
-            }
-        }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mHandler);
-    }
-
-    @Override
-    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        if (mContext.checkCallingOrSelfPermission("android.permission.DUMP")
-                != PackageManager.PERMISSION_GRANTED) {
-            pw.println("Permission Denial: can't dump DreamManager from pid="
-                    + Binder.getCallingPid()
-                    + ", uid=" + Binder.getCallingUid());
-            return;
-        }
-
-        pw.println("DREAM MANAGER (dumpsys dreams)");
-        pw.println();
-
-        pw.println("mCurrentDreamToken=" + mCurrentDreamToken);
-        pw.println("mCurrentDreamName=" + mCurrentDreamName);
-        pw.println("mCurrentDreamUserId=" + mCurrentDreamUserId);
-        pw.println("mCurrentDreamIsTest=" + mCurrentDreamIsTest);
-        pw.println();
-
-        DumpUtils.dumpAsync(mHandler, new DumpUtils.Dump() {
-            @Override
-            public void dump(PrintWriter pw) {
-                mController.dump(pw);
-            }
-        }, pw, 200);
-    }
-
-    @Override // Binder call
-    public ComponentName[] getDreamComponents() {
-        checkPermission(android.Manifest.permission.READ_DREAM_STATE);
-
-        final int userId = UserHandle.getCallingUserId();
-        final long ident = Binder.clearCallingIdentity();
-        try {
-            return getDreamComponentsForUser(userId);
-        } finally {
-            Binder.restoreCallingIdentity(ident);
-        }
-    }
-
-    @Override // Binder call
-    public void setDreamComponents(ComponentName[] componentNames) {
-        checkPermission(android.Manifest.permission.WRITE_DREAM_STATE);
-
-        final int userId = UserHandle.getCallingUserId();
-        final long ident = Binder.clearCallingIdentity();
-        try {
-            Settings.Secure.putStringForUser(mContext.getContentResolver(),
-                    Settings.Secure.SCREENSAVER_COMPONENTS,
-                    componentsToString(componentNames),
-                    userId);
-        } finally {
-            Binder.restoreCallingIdentity(ident);
-        }
-    }
-
-    @Override // Binder call
-    public ComponentName getDefaultDreamComponent() {
-        checkPermission(android.Manifest.permission.READ_DREAM_STATE);
-
-        final int userId = UserHandle.getCallingUserId();
-        final long ident = Binder.clearCallingIdentity();
-        try {
-            String name = Settings.Secure.getStringForUser(mContext.getContentResolver(),
-                    Settings.Secure.SCREENSAVER_DEFAULT_COMPONENT,
-                    userId);
-            return name == null ? null : ComponentName.unflattenFromString(name);
-        } finally {
-            Binder.restoreCallingIdentity(ident);
-        }
-    }
-
-    @Override // Binder call
-    public boolean isDreaming() {
-        checkPermission(android.Manifest.permission.READ_DREAM_STATE);
-
-        synchronized (mLock) {
-            return mCurrentDreamToken != null && !mCurrentDreamIsTest;
-        }
-    }
-
-    @Override // Binder call
-    public void dream() {
-        checkPermission(android.Manifest.permission.WRITE_DREAM_STATE);
-
-        final long ident = Binder.clearCallingIdentity();
-        try {
-            // Ask the power manager to nap.  It will eventually call back into
-            // startDream() if/when it is appropriate to start dreaming.
-            // Because napping could cause the screen to turn off immediately if the dream
-            // cannot be started, we keep one eye open and gently poke user activity.
-            long time = SystemClock.uptimeMillis();
-            mPowerManager.userActivity(time, true /*noChangeLights*/);
-            mPowerManager.nap(time);
-        } finally {
-            Binder.restoreCallingIdentity(ident);
-        }
-    }
-
-    @Override // Binder call
-    public void testDream(ComponentName dream) {
-        checkPermission(android.Manifest.permission.WRITE_DREAM_STATE);
-
-        if (dream == null) {
-            throw new IllegalArgumentException("dream must not be null");
-        }
-
-        final int callingUserId = UserHandle.getCallingUserId();
-        final int currentUserId = ActivityManager.getCurrentUser();
-        if (callingUserId != currentUserId) {
-            // This check is inherently prone to races but at least it's something.
-            Slog.w(TAG, "Aborted attempt to start a test dream while a different "
-                    + " user is active: callingUserId=" + callingUserId
-                    + ", currentUserId=" + currentUserId);
-            return;
-        }
-        final long ident = Binder.clearCallingIdentity();
-        try {
-            synchronized (mLock) {
-                startDreamLocked(dream, true /*isTest*/, callingUserId);
-            }
-        } finally {
-            Binder.restoreCallingIdentity(ident);
-        }
-    }
-
-    @Override // Binder call
-    public void awaken() {
-        checkPermission(android.Manifest.permission.WRITE_DREAM_STATE);
-
-        final long ident = Binder.clearCallingIdentity();
-        try {
-            // Treat an explicit request to awaken as user activity so that the
-            // device doesn't immediately go to sleep if the timeout expired,
-            // for example when being undocked.
-            long time = SystemClock.uptimeMillis();
-            mPowerManager.userActivity(time, false /*noChangeLights*/);
-            stopDream();
-        } finally {
-            Binder.restoreCallingIdentity(ident);
-        }
-    }
-
-    @Override // Binder call
-    public void finishSelf(IBinder token) {
-        // Requires no permission, called by Dream from an arbitrary process.
-        if (token == null) {
-            throw new IllegalArgumentException("token must not be null");
-        }
-
-        final long ident = Binder.clearCallingIdentity();
-        try {
-            if (DEBUG) {
-                Slog.d(TAG, "Dream finished: " + token);
-            }
-
-            // Note that a dream finishing and self-terminating is not
-            // itself considered user activity.  If the dream is ending because
-            // the user interacted with the device then user activity will already
-            // have been poked so the device will stay awake a bit longer.
-            // If the dream is ending on its own for other reasons and no wake
-            // locks are held and the user activity timeout has expired then the
-            // device may simply go to sleep.
-            synchronized (mLock) {
-                if (mCurrentDreamToken == token) {
-                    stopDreamLocked();
-                }
-            }
-        } finally {
-            Binder.restoreCallingIdentity(ident);
-        }
-    }
-
-    /**
-     * Called by the power manager to start a dream.
-     */
-    public void startDream() {
-        int userId = ActivityManager.getCurrentUser();
-        ComponentName dream = chooseDreamForUser(userId);
-        if (dream != null) {
-            synchronized (mLock) {
-                startDreamLocked(dream, false /*isTest*/, userId);
-            }
-        }
-    }
-
-    /**
-     * Called by the power manager to stop a dream.
-     */
-    public void stopDream() {
-        synchronized (mLock) {
-            stopDreamLocked();
-        }
-    }
-
-    private ComponentName chooseDreamForUser(int userId) {
-        ComponentName[] dreams = getDreamComponentsForUser(userId);
-        return dreams != null && dreams.length != 0 ? dreams[0] : null;
-    }
-
-    private ComponentName[] getDreamComponentsForUser(int userId) {
-        String names = Settings.Secure.getStringForUser(mContext.getContentResolver(),
-                Settings.Secure.SCREENSAVER_COMPONENTS,
-                userId);
-        ComponentName[] components = componentsFromString(names);
-
-        // first, ensure components point to valid services
-        List<ComponentName> validComponents = new ArrayList<ComponentName>();
-        if (components != null) {
-            for (ComponentName component : components) {
-                if (serviceExists(component)) {
-                    validComponents.add(component);
-                } else {
-                    Slog.w(TAG, "Dream " + component + " does not exist");
-                }
-            }
-        }
-
-        // fallback to the default dream component if necessary
-        if (validComponents.isEmpty()) {
-            ComponentName defaultDream = getDefaultDreamComponent();
-            if (defaultDream != null) {
-                Slog.w(TAG, "Falling back to default dream " + defaultDream);
-                validComponents.add(defaultDream);
-            }
-        }
-        return validComponents.toArray(new ComponentName[validComponents.size()]);
-    }
-
-    private boolean serviceExists(ComponentName name) {
-        try {
-            return name != null && mContext.getPackageManager().getServiceInfo(name, 0) != null;
-        } catch (NameNotFoundException e) {
-            return false;
-        }
-    }
-
-    private void startDreamLocked(final ComponentName name,
-            final boolean isTest, final int userId) {
-        if (Objects.equal(mCurrentDreamName, name)
-                && mCurrentDreamIsTest == isTest
-                && mCurrentDreamUserId == userId) {
-            return;
-        }
-
-        stopDreamLocked();
-
-        if (DEBUG) Slog.i(TAG, "Entering dreamland.");
-
-        final Binder newToken = new Binder();
-        mCurrentDreamToken = newToken;
-        mCurrentDreamName = name;
-        mCurrentDreamIsTest = isTest;
-        mCurrentDreamUserId = userId;
-
-        mHandler.post(new Runnable() {
-            @Override
-            public void run() {
-                mController.startDream(newToken, name, isTest, userId);
-            }
-        });
-    }
-
-    private void stopDreamLocked() {
-        if (mCurrentDreamToken != null) {
-            if (DEBUG) Slog.i(TAG, "Leaving dreamland.");
-
-            cleanupDreamLocked();
-
-            mHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    mController.stopDream();
-                }
-            });
-        }
-    }
-
-    private void cleanupDreamLocked() {
-        mCurrentDreamToken = null;
-        mCurrentDreamName = null;
-        mCurrentDreamIsTest = false;
-        mCurrentDreamUserId = 0;
-    }
-
-    private void checkPermission(String permission) {
-        if (mContext.checkCallingOrSelfPermission(permission)
-                != PackageManager.PERMISSION_GRANTED) {
-            throw new SecurityException("Access denied to process: " + Binder.getCallingPid()
-                    + ", must have permission " + permission);
-        }
-    }
-
-    private static String componentsToString(ComponentName[] componentNames) {
-        StringBuilder names = new StringBuilder();
-        if (componentNames != null) {
-            for (ComponentName componentName : componentNames) {
-                if (names.length() > 0) {
-                    names.append(',');
-                }
-                names.append(componentName.flattenToString());
-            }
-        }
-        return names.toString();
-    }
-
-    private static ComponentName[] componentsFromString(String names) {
-        if (names == null) {
-            return null;
-        }
-        String[] namesArray = names.split(",");
-        ComponentName[] componentNames = new ComponentName[namesArray.length];
-        for (int i = 0; i < namesArray.length; i++) {
-            componentNames[i] = ComponentName.unflattenFromString(namesArray[i]);
-        }
-        return componentNames;
-    }
-
-    private final DreamController.Listener mControllerListener = new DreamController.Listener() {
-        @Override
-        public void onDreamStopped(Binder token) {
-            synchronized (mLock) {
-                if (mCurrentDreamToken == token) {
-                    cleanupDreamLocked();
-                }
-            }
-        }
-    };
-
-    /**
-     * Handler for asynchronous operations performed by the dream manager.
-     * Ensures operations to {@link DreamController} are single-threaded.
-     */
-    private final class DreamHandler extends Handler {
-        public DreamHandler(Looper looper) {
-            super(looper, null, true /*async*/);
-        }
-    }
-}
diff --git a/services/java/com/android/server/power/DisplayPowerRequest.java b/services/java/com/android/server/power/DisplayPowerRequest.java
deleted file mode 100644
index 22f17d7..0000000
--- a/services/java/com/android/server/power/DisplayPowerRequest.java
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.power;
-
-import android.os.PowerManager;
-
-/**
- * Describes the requested power state of the display.
- *
- * This object is intended to describe the general characteristics of the
- * power state, such as whether the screen should be on or off and the current
- * brightness controls leaving the {@link DisplayPowerController} to manage the
- * details of how the transitions between states should occur.  The goal is for
- * the {@link PowerManagerService} to focus on the global power state and not
- * have to micro-manage screen off animations, auto-brightness and other effects.
- */
-final class DisplayPowerRequest {
-    public static final int SCREEN_STATE_OFF = 0;
-    public static final int SCREEN_STATE_DIM = 1;
-    public static final int SCREEN_STATE_BRIGHT = 2;
-
-    // The requested minimum screen power state: off, dim or bright.
-    public int screenState;
-
-    // If true, the proximity sensor overrides the screen state when an object is
-    // nearby, turning it off temporarily until the object is moved away.
-    public boolean useProximitySensor;
-
-    // The desired screen brightness in the range 0 (minimum / off) to 255 (brightest).
-    // The display power controller may choose to clamp the brightness.
-    // When auto-brightness is enabled, this field should specify a nominal default
-    // value to use while waiting for the light sensor to report enough data.
-    public int screenBrightness;
-
-    // The screen auto-brightness adjustment factor in the range -1 (dimmer) to 1 (brighter).
-    public float screenAutoBrightnessAdjustment;
-
-    // If true, enables automatic brightness control.
-    public boolean useAutoBrightness;
-
-    // If true, prevents the screen from completely turning on if it is currently off.
-    // The display does not enter a "ready" state if this flag is true and screen on is
-    // blocked.  The window manager policy blocks screen on while it prepares the keyguard to
-    // prevent the user from seeing intermediate updates.
-    //
-    // Technically, we may not block the screen itself from turning on (because that introduces
-    // extra unnecessary latency) but we do prevent content on screen from becoming
-    // visible to the user.
-    public boolean blockScreenOn;
-
-    public DisplayPowerRequest() {
-        screenState = SCREEN_STATE_BRIGHT;
-        useProximitySensor = false;
-        screenBrightness = PowerManager.BRIGHTNESS_ON;
-        screenAutoBrightnessAdjustment = 0.0f;
-        useAutoBrightness = false;
-        blockScreenOn = false;
-    }
-
-    public DisplayPowerRequest(DisplayPowerRequest other) {
-        copyFrom(other);
-    }
-
-    public void copyFrom(DisplayPowerRequest other) {
-        screenState = other.screenState;
-        useProximitySensor = other.useProximitySensor;
-        screenBrightness = other.screenBrightness;
-        screenAutoBrightnessAdjustment = other.screenAutoBrightnessAdjustment;
-        useAutoBrightness = other.useAutoBrightness;
-        blockScreenOn = other.blockScreenOn;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        return o instanceof DisplayPowerRequest
-                && equals((DisplayPowerRequest)o);
-    }
-
-    public boolean equals(DisplayPowerRequest other) {
-        return other != null
-                && screenState == other.screenState
-                && useProximitySensor == other.useProximitySensor
-                && screenBrightness == other.screenBrightness
-                && screenAutoBrightnessAdjustment == other.screenAutoBrightnessAdjustment
-                && useAutoBrightness == other.useAutoBrightness
-                && blockScreenOn == other.blockScreenOn;
-    }
-
-    @Override
-    public int hashCode() {
-        return 0; // don't care
-    }
-
-    @Override
-    public String toString() {
-        return "screenState=" + screenState
-                + ", useProximitySensor=" + useProximitySensor
-                + ", screenBrightness=" + screenBrightness
-                + ", screenAutoBrightnessAdjustment=" + screenAutoBrightnessAdjustment
-                + ", useAutoBrightness=" + useAutoBrightness
-                + ", blockScreenOn=" + blockScreenOn;
-    }
-}
diff --git a/services/java/com/android/server/print/PrintManagerService.java b/services/java/com/android/server/print/PrintManagerService.java
deleted file mode 100644
index 98acc27..0000000
--- a/services/java/com/android/server/print/PrintManagerService.java
+++ /dev/null
@@ -1,656 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.print;
-
-import android.Manifest;
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
-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.database.ContentObserver;
-import android.net.Uri;
-import android.os.Binder;
-import android.os.Bundle;
-import android.os.Process;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.print.IPrintDocumentAdapter;
-import android.print.IPrintJobStateChangeListener;
-import android.print.IPrintManager;
-import android.print.IPrinterDiscoveryObserver;
-import android.print.PrintAttributes;
-import android.print.PrintJobId;
-import android.print.PrintJobInfo;
-import android.print.PrinterId;
-import android.printservice.PrintServiceInfo;
-import android.provider.Settings;
-import android.text.TextUtils;
-import android.util.SparseArray;
-
-import com.android.internal.R;
-import com.android.internal.content.PackageMonitor;
-import com.android.internal.os.BackgroundThread;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Set;
-
-public final class PrintManagerService extends IPrintManager.Stub {
-
-    private static final char COMPONENT_NAME_SEPARATOR = ':';
-
-    private static final String EXTRA_PRINT_SERVICE_COMPONENT_NAME =
-            "EXTRA_PRINT_SERVICE_COMPONENT_NAME";
-
-    private final Object mLock = new Object();
-
-    private final Context mContext;
-
-    private final SparseArray<UserState> mUserStates = new SparseArray<UserState>();
-
-    private int mCurrentUserId = UserHandle.USER_OWNER;
-
-    public PrintManagerService(Context context) {
-        mContext = context;
-        registerContentObservers();
-        registerBoradcastReceivers();
-    }
-
-    public void systemRuning() {
-        BackgroundThread.getHandler().post(new Runnable() {
-            @Override
-            public void run() {
-                final UserState userState;
-                synchronized (mLock) {
-                    userState = getCurrentUserStateLocked();
-                    userState.updateIfNeededLocked();
-                }
-                // This is the first time we switch to this user after boot, so
-                // now is the time to remove obsolete print jobs since they
-                // are from the last boot and no application would query them.
-                userState.removeObsoletePrintJobs();
-            }
-        });
-    }
-
-    @Override
-    public Bundle print(String printJobName, IPrintDocumentAdapter adapter,
-            PrintAttributes attributes, String packageName, int appId, int userId) {
-        final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
-        final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
-        String resolvedPackageName = resolveCallingPackageNameEnforcingSecurity(packageName);
-        final UserState userState;
-        synchronized (mLock) {
-            userState = getOrCreateUserStateLocked(resolvedUserId);
-        }
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            return userState.print(printJobName, adapter, attributes,
-                    resolvedPackageName, resolvedAppId);
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-    }
-
-    @Override
-    public List<PrintJobInfo> getPrintJobInfos(int appId, int userId) {
-        final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
-        final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
-        final UserState userState;
-        synchronized (mLock) {
-            userState = getOrCreateUserStateLocked(resolvedUserId);
-        }
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            return userState.getPrintJobInfos(resolvedAppId);
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-    }
-
-    @Override
-    public PrintJobInfo getPrintJobInfo(PrintJobId printJobId, int appId, int userId) {
-        final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
-        final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
-        final UserState userState;
-        synchronized (mLock) {
-            userState = getOrCreateUserStateLocked(resolvedUserId);
-        }
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            return userState.getPrintJobInfo(printJobId, resolvedAppId);
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-    }
-
-    @Override
-    public void cancelPrintJob(PrintJobId printJobId, int appId, int userId) {
-        final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
-        final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
-        final UserState userState;
-        synchronized (mLock) {
-            userState = getOrCreateUserStateLocked(resolvedUserId);
-        }
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            userState.cancelPrintJob(printJobId, resolvedAppId);
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-    }
-
-    @Override
-    public void restartPrintJob(PrintJobId printJobId, int appId, int userId) {
-        final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
-        final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
-        final UserState userState;
-        synchronized (mLock) {
-            userState = getOrCreateUserStateLocked(resolvedUserId);
-        }
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            userState.restartPrintJob(printJobId, resolvedAppId);
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-    }
-
-    @Override
-    public List<PrintServiceInfo> getEnabledPrintServices(int userId) {
-        final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
-        final UserState userState;
-        synchronized (mLock) {
-            userState = getOrCreateUserStateLocked(resolvedUserId);
-        }
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            return userState.getEnabledPrintServices();
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-    }
-
-    @Override
-    public List<PrintServiceInfo> getInstalledPrintServices(int userId) {
-        final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
-        final UserState userState;
-        synchronized (mLock) {
-            userState = getOrCreateUserStateLocked(resolvedUserId);
-        }
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            return userState.getInstalledPrintServices();
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-    }
-
-    @Override
-    public void createPrinterDiscoverySession(IPrinterDiscoveryObserver observer,
-            int userId) {
-        final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
-        final UserState userState;
-        synchronized (mLock) {
-            userState = getOrCreateUserStateLocked(resolvedUserId);
-        }
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            userState.createPrinterDiscoverySession(observer);
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-    }
-
-    @Override
-    public void destroyPrinterDiscoverySession(IPrinterDiscoveryObserver observer,
-            int userId) {
-        final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
-        final UserState userState;
-        synchronized (mLock) {
-            userState = getOrCreateUserStateLocked(resolvedUserId);
-        }
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            userState.destroyPrinterDiscoverySession(observer);
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-    }
-
-    @Override
-    public void startPrinterDiscovery(IPrinterDiscoveryObserver observer,
-            List<PrinterId> priorityList, int userId) {
-        final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
-        final UserState userState;
-        synchronized (mLock) {
-            userState = getOrCreateUserStateLocked(resolvedUserId);
-        }
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            userState.startPrinterDiscovery(observer, priorityList);
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-    }
-
-    @Override
-    public void stopPrinterDiscovery(IPrinterDiscoveryObserver observer, int userId) {
-        final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
-        final UserState userState;
-        synchronized (mLock) {
-            userState = getOrCreateUserStateLocked(resolvedUserId);
-        }
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            userState.stopPrinterDiscovery(observer);
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-    }
-
-    @Override
-    public void validatePrinters(List<PrinterId> printerIds, int userId) {
-        final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
-        final UserState userState;
-        synchronized (mLock) {
-            userState = getOrCreateUserStateLocked(resolvedUserId);
-        }
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            userState.validatePrinters(printerIds);
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-    }
-
-    @Override
-    public void startPrinterStateTracking(PrinterId printerId, int userId) {
-        final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
-        final UserState userState;
-        synchronized (mLock) {
-            userState = getOrCreateUserStateLocked(resolvedUserId);
-        }
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            userState.startPrinterStateTracking(printerId);
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-    }
-
-    @Override
-    public void stopPrinterStateTracking(PrinterId printerId, int userId) {
-        final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
-        final UserState userState;
-        synchronized (mLock) {
-            userState = getOrCreateUserStateLocked(resolvedUserId);
-        }
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            userState.stopPrinterStateTracking(printerId);
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-    }
-
-    @Override
-    public void addPrintJobStateChangeListener(IPrintJobStateChangeListener listener,
-            int appId, int userId) throws RemoteException {
-        final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
-        final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
-        final UserState userState;
-        synchronized (mLock) {
-            userState = getOrCreateUserStateLocked(resolvedUserId);
-        }
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            userState.addPrintJobStateChangeListener(listener, resolvedAppId);
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-    }
-
-    @Override
-    public void removePrintJobStateChangeListener(IPrintJobStateChangeListener listener,
-            int userId) {
-        final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
-        final UserState userState;
-        synchronized (mLock) {
-            userState = getOrCreateUserStateLocked(resolvedUserId);
-        }
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            userState.removePrintJobStateChangeListener(listener);
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-    }
-
-    @Override
-    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP)
-                != PackageManager.PERMISSION_GRANTED) {
-            pw.println("Permission Denial: can't dump PrintManager from from pid="
-                    + Binder.getCallingPid()
-                    + ", uid=" + Binder.getCallingUid());
-            return;
-        }
-
-        synchronized (mLock) {
-            final long identity = Binder.clearCallingIdentity();
-            try {
-                pw.println("PRINT MANAGER STATE (dumpsys print)");
-                final int userStateCount = mUserStates.size();
-                for (int i = 0; i < userStateCount; i++) {
-                    UserState userState = mUserStates.valueAt(i);
-                    userState.dump(fd, pw, "");
-                    pw.println();
-                }
-            } finally {
-                Binder.restoreCallingIdentity(identity);
-            }
-        }
-    }
-
-    private void registerContentObservers() {
-        final Uri enabledPrintServicesUri = Settings.Secure.getUriFor(
-                Settings.Secure.ENABLED_PRINT_SERVICES);
-
-        ContentObserver observer = new ContentObserver(BackgroundThread.getHandler()) {
-            @Override
-            public void onChange(boolean selfChange, Uri uri) {
-                if (enabledPrintServicesUri.equals(uri)) {
-                    synchronized (mLock) {
-                        UserState userState = getCurrentUserStateLocked();
-                        userState.updateIfNeededLocked();
-                    }
-                }
-            }
-        };
-
-        mContext.getContentResolver().registerContentObserver(enabledPrintServicesUri,
-                false, observer, UserHandle.USER_ALL);
-    }
-
-    private void registerBoradcastReceivers() {
-        PackageMonitor monitor = new PackageMonitor() {
-            @Override
-            public boolean onPackageChanged(String packageName, int uid, String[] components) {
-                synchronized (mLock) {
-                    UserState userState = getOrCreateUserStateLocked(getChangingUserId());
-                    Iterator<ComponentName> iterator = userState.getEnabledServices().iterator();
-                    while (iterator.hasNext()) {
-                        ComponentName componentName = iterator.next();
-                        if (packageName.equals(componentName.getPackageName())) {
-                            userState.updateIfNeededLocked();
-                            return true;
-                        }
-                    }
-                }
-                return false;
-            }
-
-            @Override
-            public void onPackageRemoved(String packageName, int uid) {
-                synchronized (mLock) {
-                    UserState userState = getOrCreateUserStateLocked(getChangingUserId());
-                    Iterator<ComponentName> iterator = userState.getEnabledServices().iterator();
-                    while (iterator.hasNext()) {
-                        ComponentName componentName = iterator.next();
-                        if (packageName.equals(componentName.getPackageName())) {
-                            iterator.remove();
-                            persistComponentNamesToSettingLocked(
-                                    Settings.Secure.ENABLED_PRINT_SERVICES,
-                                    userState.getEnabledServices(), getChangingUserId());
-                            userState.updateIfNeededLocked();
-                            return;
-                        }
-                    }
-                }
-            }
-
-            @Override
-            public boolean onHandleForceStop(Intent intent, String[] stoppedPackages,
-                    int uid, boolean doit) {
-                synchronized (mLock) {
-                    UserState userState = getOrCreateUserStateLocked(getChangingUserId());
-                    boolean stoppedSomePackages = false;
-                    Iterator<ComponentName> iterator = userState.getEnabledServices().iterator();
-                    while (iterator.hasNext()) {
-                        ComponentName componentName = iterator.next();
-                        String componentPackage = componentName.getPackageName();
-                        for (String stoppedPackage : stoppedPackages) {
-                            if (componentPackage.equals(stoppedPackage)) {
-                                if (!doit) {
-                                    return true;
-                                }
-                                stoppedSomePackages = true;
-                                break;
-                            }
-                        }
-                    }
-                    if (stoppedSomePackages) {
-                        userState.updateIfNeededLocked();
-                    }
-                    return false;
-                }
-            }
-
-            @Override
-            public void onPackageAdded(String packageName, int uid) {
-                Intent intent = new Intent(android.printservice.PrintService.SERVICE_INTERFACE);
-                intent.setPackage(packageName);
-
-                List<ResolveInfo> installedServices = mContext.getPackageManager()
-                        .queryIntentServicesAsUser(intent, PackageManager.GET_SERVICES,
-                                getChangingUserId());
-
-                if (installedServices == null) {
-                    return;
-                }
-
-                final int installedServiceCount = installedServices.size();
-                for (int i = 0; i < installedServiceCount; i++) {
-                    ServiceInfo serviceInfo = installedServices.get(i).serviceInfo;
-                    ComponentName component = new ComponentName(serviceInfo.packageName,
-                            serviceInfo.name);
-                    String label = serviceInfo.loadLabel(mContext.getPackageManager()).toString();
-                    showEnableInstalledPrintServiceNotification(component, label,
-                            getChangingUserId());
-                }
-            }
-
-            private void persistComponentNamesToSettingLocked(String settingName,
-                    Set<ComponentName> componentNames, int userId) {
-                StringBuilder builder = new StringBuilder();
-                for (ComponentName componentName : componentNames) {
-                    if (builder.length() > 0) {
-                        builder.append(COMPONENT_NAME_SEPARATOR);
-                    }
-                    builder.append(componentName.flattenToShortString());
-                }
-                Settings.Secure.putStringForUser(mContext.getContentResolver(),
-                        settingName, builder.toString(), userId);
-            }
-        };
-
-        // package changes
-        monitor.register(mContext, BackgroundThread.getHandler().getLooper(),
-                UserHandle.ALL, true);
-
-        // user changes
-        IntentFilter intentFilter = new IntentFilter();
-        intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
-        intentFilter.addAction(Intent.ACTION_USER_REMOVED);
-
-        mContext.registerReceiverAsUser(new BroadcastReceiver() {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                String action = intent.getAction();
-                if (Intent.ACTION_USER_SWITCHED.equals(action)) {
-                    switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
-                } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
-                    removeUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
-                }
-            }
-        }, UserHandle.ALL, intentFilter, null, BackgroundThread.getHandler());
-    }
-
-    private UserState getCurrentUserStateLocked() {
-        return getOrCreateUserStateLocked(mCurrentUserId);
-    }
-
-    private UserState getOrCreateUserStateLocked(int userId) {
-        UserState userState = mUserStates.get(userId);
-        if (userState == null) {
-            userState = new UserState(mContext, userId, mLock);
-            mUserStates.put(userId, userState);
-        }
-        return userState;
-    }
-
-    private void switchUser(int newUserId) {
-        UserState userState;
-        synchronized (mLock) {
-            if (newUserId == mCurrentUserId) {
-                return;
-            }
-            mCurrentUserId = newUserId;
-            userState = mUserStates.get(mCurrentUserId);
-            if (userState == null) {
-                userState = getCurrentUserStateLocked();
-                userState.updateIfNeededLocked();
-            } else {
-                userState.updateIfNeededLocked();
-            }
-        }
-        // This is the first time we switch to this user after boot, so
-        // now is the time to remove obsolete print jobs since they
-        // are from the last boot and no application would query them.
-        userState.removeObsoletePrintJobs();
-    }
-
-    private void removeUser(int removedUserId) {
-        synchronized (mLock) {
-            UserState userState = mUserStates.get(removedUserId);
-            if (userState != null) {
-                userState.destroyLocked();
-                mUserStates.remove(removedUserId);
-            }
-        }
-    }
-
-    private int resolveCallingAppEnforcingPermissions(int appId) {
-        final int callingUid = Binder.getCallingUid();
-        if (callingUid == 0 || callingUid == Process.SYSTEM_UID
-                || callingUid == Process.SHELL_UID) {
-            return appId;
-        }
-        final int callingAppId = UserHandle.getAppId(callingUid);
-        if (appId == callingAppId) {
-            return appId;
-        }
-        if (mContext.checkCallingPermission(
-                "com.android.printspooler.permission.ACCESS_ALL_PRINT_JOBS")
-                != PackageManager.PERMISSION_GRANTED) {
-            throw new SecurityException("Call from app " + callingAppId + " as app "
-                    + appId + " without com.android.printspooler.permission"
-                    + ".ACCESS_ALL_PRINT_JOBS");
-        }
-        return appId;
-    }
-
-    private int resolveCallingUserEnforcingPermissions(int userId) {
-        final int callingUid = Binder.getCallingUid();
-        if (callingUid == 0 || callingUid == Process.SYSTEM_UID
-                || callingUid == Process.SHELL_UID) {
-            return userId;
-        }
-        final int callingUserId = UserHandle.getUserId(callingUid);
-        if (callingUserId == userId) {
-            return userId;
-        }
-        if (mContext.checkCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL)
-                != PackageManager.PERMISSION_GRANTED
-            ||  mContext.checkCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS)
-                != PackageManager.PERMISSION_GRANTED) {
-            if (userId == UserHandle.USER_CURRENT_OR_SELF) {
-                return callingUserId;
-            }
-            throw new SecurityException("Call from user " + callingUserId + " as user "
-                + userId + " without permission INTERACT_ACROSS_USERS or "
-                + "INTERACT_ACROSS_USERS_FULL not allowed.");
-        }
-        if (userId == UserHandle.USER_CURRENT || userId == UserHandle.USER_CURRENT_OR_SELF) {
-            return mCurrentUserId;
-        }
-        throw new IllegalArgumentException("Calling user can be changed to only "
-                + "UserHandle.USER_CURRENT or UserHandle.USER_CURRENT_OR_SELF.");
-    }
-
-    private String resolveCallingPackageNameEnforcingSecurity(String packageName) {
-        if (TextUtils.isEmpty(packageName)) {
-            return null;
-        }
-        String[] packages = mContext.getPackageManager().getPackagesForUid(
-                Binder.getCallingUid());
-        final int packageCount = packages.length;
-        for (int i = 0; i < packageCount; i++) {
-            if (packageName.equals(packages[i])) {
-                return packageName;
-            }
-        }
-        return null;
-    }
-
-    private void showEnableInstalledPrintServiceNotification(ComponentName component,
-            String label, int userId) {
-        UserHandle userHandle = new UserHandle(userId);
-
-        Intent intent = new Intent(Settings.ACTION_PRINT_SETTINGS);
-        intent.putExtra(EXTRA_PRINT_SERVICE_COMPONENT_NAME, component.flattenToString());
-
-        PendingIntent pendingIntent = PendingIntent.getActivityAsUser(mContext, 0, intent,
-                PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_CANCEL_CURRENT, null, userHandle);
-
-        Notification.Builder builder = new Notification.Builder(mContext)
-                .setSmallIcon(R.drawable.ic_print)
-                .setContentTitle(mContext.getString(R.string.print_service_installed_title, label))
-                .setContentText(mContext.getString(R.string.print_service_installed_message))
-                .setContentIntent(pendingIntent)
-                .setWhen(System.currentTimeMillis())
-                .setAutoCancel(true)
-                .setShowWhen(true);
-
-        NotificationManager notificationManager = (NotificationManager) mContext
-                .getSystemService(Context.NOTIFICATION_SERVICE);
-
-        String notificationTag = getClass().getName() + ":" + component.flattenToString();
-        notificationManager.notifyAsUser(notificationTag, 0, builder.build(),
-                userHandle);
-    }
-}
diff --git a/services/java/com/android/server/wm/DisplayContent.java b/services/java/com/android/server/wm/DisplayContent.java
deleted file mode 100644
index d358b4c..0000000
--- a/services/java/com/android/server/wm/DisplayContent.java
+++ /dev/null
@@ -1,523 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm;
-
-import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID;
-import static com.android.server.wm.WindowManagerService.DEBUG_STACK;
-import static com.android.server.wm.WindowManagerService.DEBUG_VISIBILITY;
-import static com.android.server.wm.WindowManagerService.TAG;
-
-import android.app.ActivityManager.StackBoxInfo;
-import android.graphics.Rect;
-import android.graphics.Region;
-import android.os.Debug;
-import android.util.EventLog;
-import android.util.Slog;
-import android.view.Display;
-import android.view.DisplayInfo;
-import com.android.server.EventLogTags;
-
-import java.io.PrintWriter;
-import java.util.ArrayList;
-
-class DisplayContentList extends ArrayList<DisplayContent> {
-}
-
-/**
- * Utility class for keeping track of the WindowStates and other pertinent contents of a
- * particular Display.
- *
- * IMPORTANT: No method from this class should ever be used without holding
- * WindowManagerService.mWindowMap.
- */
-class DisplayContent {
-
-    /** Unique identifier of this stack. */
-    private final int mDisplayId;
-
-    /** Z-ordered (bottom-most first) list of all Window objects. Assigned to an element
-     * from mDisplayWindows; */
-    private WindowList mWindows = new WindowList();
-
-    // This protects the following display size properties, so that
-    // getDisplaySize() doesn't need to acquire the global lock.  This is
-    // needed because the window manager sometimes needs to use ActivityThread
-    // while it has its global state locked (for example to load animation
-    // resources), but the ActivityThread also needs get the current display
-    // size sometimes when it has its package lock held.
-    //
-    // These will only be modified with both mWindowMap and mDisplaySizeLock
-    // held (in that order) so the window manager doesn't need to acquire this
-    // lock when needing these values in its normal operation.
-    final Object mDisplaySizeLock = new Object();
-    int mInitialDisplayWidth = 0;
-    int mInitialDisplayHeight = 0;
-    int mInitialDisplayDensity = 0;
-    int mBaseDisplayWidth = 0;
-    int mBaseDisplayHeight = 0;
-    int mBaseDisplayDensity = 0;
-    private final DisplayInfo mDisplayInfo = new DisplayInfo();
-    private final Display mDisplay;
-
-    Rect mBaseDisplayRect = new Rect();
-
-    // Accessed directly by all users.
-    boolean layoutNeeded;
-    int pendingLayoutChanges;
-    final boolean isDefaultDisplay;
-
-    /**
-     * Window tokens that are in the process of exiting, but still
-     * on screen for animations.
-     */
-    final ArrayList<WindowToken> mExitingTokens = new ArrayList<WindowToken>();
-
-    /**
-     * Application tokens that are in the process of exiting, but still
-     * on screen for animations.
-     */
-    final AppTokenList mExitingAppTokens = new AppTokenList();
-
-    /** Array containing the home StackBox and possibly one more which would contain apps. Array
-     * is stored in display order with the current bottom stack at 0. */
-    private ArrayList<StackBox> mStackBoxes = new ArrayList<StackBox>();
-
-    /** True when the home StackBox is at the top of mStackBoxes, false otherwise. */
-    private TaskStack mHomeStack = null;
-
-    /** Detect user tapping outside of current focused stack bounds .*/
-    StackTapPointerEventListener mTapDetector;
-
-    /** Detect user tapping outside of current focused stack bounds .*/
-    Region mTouchExcludeRegion = new Region();
-
-    /** Save allocating when retrieving tasks */
-    private ArrayList<Task> mTaskHistory = new ArrayList<Task>();
-
-    /** Save allocating when calculating rects */
-    Rect mTmpRect = new Rect();
-
-    final WindowManagerService mService;
-
-    /**
-     * @param display May not be null.
-     * @param service TODO(cmautner):
-     */
-    DisplayContent(Display display, WindowManagerService service) {
-        mDisplay = display;
-        mDisplayId = display.getDisplayId();
-        display.getDisplayInfo(mDisplayInfo);
-        isDefaultDisplay = mDisplayId == Display.DEFAULT_DISPLAY;
-        mService = service;
-
-        StackBox newBox = new StackBox(service, this, null);
-        mStackBoxes.add(newBox);
-        TaskStack newStack = new TaskStack(service, HOME_STACK_ID, this);
-        newStack.mStackBox = newBox;
-        newBox.mStack = newStack;
-        mHomeStack = newStack;
-    }
-
-    int getDisplayId() {
-        return mDisplayId;
-    }
-
-    WindowList getWindowList() {
-        return mWindows;
-    }
-
-    Display getDisplay() {
-        return mDisplay;
-    }
-
-    DisplayInfo getDisplayInfo() {
-        return mDisplayInfo;
-    }
-
-    /**
-     * Returns true if the specified UID has access to this display.
-     */
-    public boolean hasAccess(int uid) {
-        return mDisplay.hasAccess(uid);
-    }
-
-    boolean homeOnTop() {
-        return mStackBoxes.get(0).mStack != mHomeStack;
-    }
-
-    public boolean isPrivate() {
-        return (mDisplay.getFlags() & Display.FLAG_PRIVATE) != 0;
-    }
-
-    /**
-     * Retrieve the tasks on this display in stack order from the bottommost TaskStack up.
-     * @return All the Tasks, in order, on this display.
-     */
-    ArrayList<Task> getTasks() {
-        return mTaskHistory;
-    }
-
-    void addTask(Task task, boolean toTop) {
-        mTaskHistory.remove(task);
-
-        final int userId = task.mUserId;
-        int taskNdx;
-        final int numTasks = mTaskHistory.size();
-        if (toTop) {
-            for (taskNdx = numTasks - 1; taskNdx >= 0; --taskNdx) {
-                if (mTaskHistory.get(taskNdx).mUserId == userId) {
-                    break;
-                }
-            }
-            ++taskNdx;
-        } else {
-            for (taskNdx = 0; taskNdx < numTasks; ++taskNdx) {
-                if (mTaskHistory.get(taskNdx).mUserId == userId) {
-                    break;
-                }
-            }
-        }
-
-        mTaskHistory.add(taskNdx, task);
-        EventLog.writeEvent(EventLogTags.WM_TASK_MOVED, task.taskId, toTop ? 1 : 0, taskNdx);
-    }
-
-    void removeTask(Task task) {
-        mTaskHistory.remove(task);
-    }
-
-    TaskStack getHomeStack() {
-        return mHomeStack;
-    }
-
-    void updateDisplayInfo() {
-        mDisplay.getDisplayInfo(mDisplayInfo);
-    }
-
-    void getLogicalDisplayRect(Rect out) {
-        updateDisplayInfo();
-        // Uses same calculation as in LogicalDisplay#configureDisplayInTransactionLocked.
-        int width = mDisplayInfo.logicalWidth;
-        int left = (mBaseDisplayWidth - width) / 2;
-        int height = mDisplayInfo.logicalHeight;
-        int top = (mBaseDisplayHeight - height) / 2;
-        out.set(left, top, left + width, top + height);
-    }
-
-    /** @return The number of tokens in all of the Tasks on this display. */
-    int numTokens() {
-        int count = 0;
-        for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
-            count += mTaskHistory.get(taskNdx).mAppTokens.size();
-        }
-        return count;
-    }
-
-    /** Refer to {@link WindowManagerService#createStack(int, int, int, float)} */
-    TaskStack createStack(int stackId, int relativeStackBoxId, int position, float weight) {
-        TaskStack newStack = null;
-        if (DEBUG_STACK) Slog.d(TAG, "createStack: stackId=" + stackId + " relativeStackBoxId="
-                + relativeStackBoxId + " position=" + position + " weight=" + weight);
-        if (stackId == HOME_STACK_ID) {
-            if (mStackBoxes.size() != 1) {
-                throw new IllegalArgumentException("createStack: HOME_STACK_ID (0) not first.");
-            }
-            newStack = mHomeStack;
-        } else {
-            int stackBoxNdx;
-            for (stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
-                final StackBox box = mStackBoxes.get(stackBoxNdx);
-                if (position == StackBox.TASK_STACK_GOES_OVER
-                        || position == StackBox.TASK_STACK_GOES_UNDER) {
-                    // Position indicates a new box is added at top level only.
-                    if (box.contains(relativeStackBoxId)) {
-                        StackBox newBox = new StackBox(mService, this, null);
-                        newStack = new TaskStack(mService, stackId, this);
-                        newStack.mStackBox = newBox;
-                        newBox.mStack = newStack;
-                        final int offset = position == StackBox.TASK_STACK_GOES_OVER ? 1 : 0;
-                        if (DEBUG_STACK) Slog.d(TAG, "createStack: inserting stack at " +
-                                (stackBoxNdx + offset));
-                        mStackBoxes.add(stackBoxNdx + offset, newBox);
-                        break;
-                    }
-                } else {
-                    // Remaining position values indicate a box must be split.
-                    newStack = box.split(stackId, relativeStackBoxId, position, weight);
-                    if (newStack != null) {
-                        break;
-                    }
-                }
-            }
-            if (stackBoxNdx < 0) {
-                throw new IllegalArgumentException("createStack: stackBoxId " + relativeStackBoxId
-                        + " not found.");
-            }
-        }
-        if (newStack != null) {
-            layoutNeeded = true;
-        }
-        EventLog.writeEvent(EventLogTags.WM_STACK_CREATED, stackId, relativeStackBoxId, position,
-                (int)(weight * 100 + 0.5));
-        return newStack;
-    }
-
-    /** Refer to {@link WindowManagerService#resizeStackBox(int, float)} */
-    boolean resizeStack(int stackBoxId, float weight) {
-        for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
-            final StackBox box = mStackBoxes.get(stackBoxNdx);
-            if (box.resize(stackBoxId, weight)) {
-                layoutNeeded = true;
-                return true;
-            }
-        }
-        return false;
-    }
-
-    void addStackBox(StackBox box, boolean toTop) {
-        if (mStackBoxes.size() >= 2) {
-            throw new RuntimeException("addStackBox: Too many toplevel StackBoxes!");
-        }
-        mStackBoxes.add(toTop ? mStackBoxes.size() : 0, box);
-    }
-
-    void removeStackBox(StackBox box) {
-        if (DEBUG_STACK) Slog.d(TAG, "removeStackBox: box=" + box);
-        final TaskStack stack = box.mStack;
-        if (stack != null && stack.mStackId == HOME_STACK_ID) {
-            // Never delete the home stack, even if it is empty.
-            if (DEBUG_STACK) Slog.d(TAG, "removeStackBox: Not deleting home stack.");
-            return;
-        }
-        mStackBoxes.remove(box);
-    }
-
-    StackBoxInfo getStackBoxInfo(StackBox box) {
-        StackBoxInfo info = new StackBoxInfo();
-        info.stackBoxId = box.mStackBoxId;
-        info.weight = box.mWeight;
-        info.vertical = box.mVertical;
-        info.bounds = new Rect(box.mBounds);
-        if (box.mStack != null) {
-            info.stackId = box.mStack.mStackId;
-            // ActivityManagerService will fill in the StackInfo.
-        } else {
-            info.stackId = -1;
-            info.children = new StackBoxInfo[2];
-            info.children[0] = getStackBoxInfo(box.mFirst);
-            info.children[1] = getStackBoxInfo(box.mSecond);
-        }
-        return info;
-    }
-
-    ArrayList<StackBoxInfo> getStackBoxInfos() {
-        ArrayList<StackBoxInfo> list = new ArrayList<StackBoxInfo>();
-        for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
-            list.add(getStackBoxInfo(mStackBoxes.get(stackBoxNdx)));
-        }
-        return list;
-    }
-
-    /**
-     * Move the home StackBox to the top or bottom of mStackBoxes. That is the only place
-     * it is allowed to be. This is a nop if the home StackBox is already in the correct position.
-     * @param toTop Move home to the top of mStackBoxes if true, to the bottom if false.
-     * @return true if a change was made, false otherwise.
-     */
-    boolean moveHomeStackBox(boolean toTop) {
-        if (DEBUG_STACK) Slog.d(TAG, "moveHomeStackBox: toTop=" + toTop + " Callers=" +
-                Debug.getCallers(4));
-        EventLog.writeEvent(EventLogTags.WM_HOME_STACK_MOVED, toTop ? 1 : 0);
-        switch (mStackBoxes.size()) {
-            case 0: throw new RuntimeException("moveHomeStackBox: No home StackBox!");
-            case 1: return false; // Only the home StackBox exists.
-            case 2:
-                if (homeOnTop() ^ toTop) {
-                    mStackBoxes.add(mStackBoxes.remove(0));
-                    return true;
-                }
-                return false;
-            default: throw new RuntimeException("moveHomeStackBox: Too many toplevel StackBoxes!");
-        }
-    }
-
-    /**
-     * Propagate the new bounds to all child stack boxes, applying weights as we move down.
-     * @param contentRect The bounds to apply at the top level.
-     */
-    boolean setStackBoxSize(Rect contentRect) {
-        boolean change = false;
-        for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
-            change |= mStackBoxes.get(stackBoxNdx).setStackBoxSizes(contentRect, true);
-        }
-        return change;
-    }
-
-    Rect getStackBounds(int stackId) {
-        for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
-            Rect bounds = mStackBoxes.get(stackBoxNdx).getStackBounds(stackId);
-            if (bounds != null) {
-                return bounds;
-            }
-        }
-        return null;
-    }
-
-    int stackIdFromPoint(int x, int y) {
-        StackBox topBox = mStackBoxes.get(mStackBoxes.size() - 1);
-        return topBox.stackIdFromPoint(x, y);
-    }
-
-    void setTouchExcludeRegion(TaskStack focusedStack) {
-        mTouchExcludeRegion.set(mBaseDisplayRect);
-        WindowList windows = getWindowList();
-        for (int i = windows.size() - 1; i >= 0; --i) {
-            final WindowState win = windows.get(i);
-            final TaskStack stack = win.getStack();
-            if (win.isVisibleLw() && stack != null && stack != focusedStack) {
-                mTmpRect.set(win.mVisibleFrame);
-                mTmpRect.intersect(win.mVisibleInsets);
-                mTouchExcludeRegion.op(mTmpRect, Region.Op.DIFFERENCE);
-            }
-        }
-    }
-
-    void switchUserStacks(int oldUserId, int newUserId) {
-        final WindowList windows = getWindowList();
-        for (int i = 0; i < windows.size(); i++) {
-            final WindowState win = windows.get(i);
-            if (win.isHiddenFromUserLocked()) {
-                if (DEBUG_VISIBILITY) Slog.w(TAG, "user changing " + newUserId + " hiding "
-                        + win + ", attrs=" + win.mAttrs.type + ", belonging to "
-                        + win.mOwnerUid);
-                win.hideLw(false);
-            }
-        }
-
-        for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
-            mStackBoxes.get(stackBoxNdx).switchUserStacks(newUserId);
-        }
-    }
-
-    void resetAnimationBackgroundAnimator() {
-        for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
-            mStackBoxes.get(stackBoxNdx).resetAnimationBackgroundAnimator();
-        }
-    }
-
-    boolean animateDimLayers() {
-        boolean result = false;
-        for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
-            result |= mStackBoxes.get(stackBoxNdx).animateDimLayers();
-        }
-        return result;
-    }
-
-    void resetDimming() {
-        for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
-            mStackBoxes.get(stackBoxNdx).resetDimming();
-        }
-    }
-
-    boolean isDimming() {
-        boolean result = false;
-        for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
-            result |= mStackBoxes.get(stackBoxNdx).isDimming();
-        }
-        return result;
-    }
-
-    void stopDimmingIfNeeded() {
-        for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
-            mStackBoxes.get(stackBoxNdx).stopDimmingIfNeeded();
-        }
-    }
-
-    void close() {
-        for (int stackBoxNdx = mStackBoxes.size() - 1; stackBoxNdx >= 0; --stackBoxNdx) {
-            mStackBoxes.get(stackBoxNdx).close();
-        }
-    }
-
-    public void dump(String prefix, PrintWriter pw) {
-        pw.print(prefix); pw.print("Display: mDisplayId="); pw.println(mDisplayId);
-        final String subPrefix = "  " + prefix;
-        pw.print(subPrefix); pw.print("init="); pw.print(mInitialDisplayWidth); pw.print("x");
-            pw.print(mInitialDisplayHeight); pw.print(" "); pw.print(mInitialDisplayDensity);
-            pw.print("dpi");
-            if (mInitialDisplayWidth != mBaseDisplayWidth
-                    || mInitialDisplayHeight != mBaseDisplayHeight
-                    || mInitialDisplayDensity != mBaseDisplayDensity) {
-                pw.print(" base=");
-                pw.print(mBaseDisplayWidth); pw.print("x"); pw.print(mBaseDisplayHeight);
-                pw.print(" "); pw.print(mBaseDisplayDensity); pw.print("dpi");
-            }
-            pw.print(" cur=");
-            pw.print(mDisplayInfo.logicalWidth);
-            pw.print("x"); pw.print(mDisplayInfo.logicalHeight);
-            pw.print(" app=");
-            pw.print(mDisplayInfo.appWidth);
-            pw.print("x"); pw.print(mDisplayInfo.appHeight);
-            pw.print(" rng="); pw.print(mDisplayInfo.smallestNominalAppWidth);
-            pw.print("x"); pw.print(mDisplayInfo.smallestNominalAppHeight);
-            pw.print("-"); pw.print(mDisplayInfo.largestNominalAppWidth);
-            pw.print("x"); pw.println(mDisplayInfo.largestNominalAppHeight);
-            pw.print(subPrefix); pw.print("layoutNeeded="); pw.println(layoutNeeded);
-        for (int boxNdx = 0; boxNdx < mStackBoxes.size(); ++boxNdx) {
-            pw.print(prefix); pw.print("StackBox #"); pw.println(boxNdx);
-            mStackBoxes.get(boxNdx).dump(prefix + "  ", pw);
-        }
-        int ndx = numTokens();
-        if (ndx > 0) {
-            pw.println();
-            pw.println("  Application tokens in Z order:");
-            getTasks();
-            for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
-                AppTokenList tokens = mTaskHistory.get(taskNdx).mAppTokens;
-                for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
-                    final AppWindowToken wtoken = tokens.get(tokenNdx);
-                    pw.print("  App #"); pw.print(ndx--);
-                            pw.print(' '); pw.print(wtoken); pw.println(":");
-                    wtoken.dump(pw, "    ");
-                }
-            }
-        }
-        if (mExitingTokens.size() > 0) {
-            pw.println();
-            pw.println("  Exiting tokens:");
-            for (int i=mExitingTokens.size()-1; i>=0; i--) {
-                WindowToken token = mExitingTokens.get(i);
-                pw.print("  Exiting #"); pw.print(i);
-                pw.print(' '); pw.print(token);
-                pw.println(':');
-                token.dump(pw, "    ");
-            }
-        }
-        if (mExitingAppTokens.size() > 0) {
-            pw.println();
-            pw.println("  Exiting application tokens:");
-            for (int i=mExitingAppTokens.size()-1; i>=0; i--) {
-                WindowToken token = mExitingAppTokens.get(i);
-                pw.print("  Exiting App #"); pw.print(i);
-                  pw.print(' '); pw.print(token);
-                  pw.println(':');
-                  token.dump(pw, "    ");
-            }
-        }
-        pw.println();
-    }
-}
diff --git a/services/java/com/android/server/wm/StackBox.java b/services/java/com/android/server/wm/StackBox.java
deleted file mode 100644
index d351925..0000000
--- a/services/java/com/android/server/wm/StackBox.java
+++ /dev/null
@@ -1,414 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm;
-
-import android.graphics.Rect;
-import android.util.Slog;
-
-import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID;
-import static com.android.server.wm.WindowManagerService.DEBUG_STACK;
-import static com.android.server.wm.WindowManagerService.TAG;
-
-import java.io.PrintWriter;
-
-public class StackBox {
-    /** Used with {@link WindowManagerService#createStack}. Dependent on Configuration LTR/RTL. */
-    public static final int TASK_STACK_GOES_BEFORE = 0;
-    /** Used with {@link WindowManagerService#createStack}. Dependent on Configuration LTR/RTL. */
-    public static final int TASK_STACK_GOES_AFTER = 1;
-    /** Used with {@link WindowManagerService#createStack}. Horizontal to left of. */
-    public static final int TASK_STACK_TO_LEFT_OF = 2;
-    /** Used with {@link WindowManagerService#createStack}. Horizontal to right of. */
-    public static final int TASK_STACK_TO_RIGHT_OF = 3;
-    /** Used with {@link WindowManagerService#createStack}. Vertical: lower t/b Rect values. */
-    public static final int TASK_STACK_GOES_ABOVE = 4;
-    /** Used with {@link WindowManagerService#createStack}. Vertical: higher t/b Rect values. */
-    public static final int TASK_STACK_GOES_BELOW = 5;
-    /** Used with {@link WindowManagerService#createStack}. Put on a higher layer on display. */
-    public static final int TASK_STACK_GOES_OVER = 6;
-    /** Used with {@link WindowManagerService#createStack}. Put on a lower layer on display. */
-    public static final int TASK_STACK_GOES_UNDER = 7;
-
-    static int sCurrentBoxId = 0;
-
-    /** Unique id for this box */
-    final int mStackBoxId;
-
-    /** The service */
-    final WindowManagerService mService;
-
-    /** The display this box sits in. */
-    final DisplayContent mDisplayContent;
-
-    /** Non-null indicates this is mFirst or mSecond of a parent StackBox. Null indicates this
-     * is this entire size of mDisplayContent. */
-    StackBox mParent;
-
-    /** First child, this is null exactly when mStack is non-null. */
-    StackBox mFirst;
-
-    /** Second child, this is null exactly when mStack is non-null. */
-    StackBox mSecond;
-
-    /** Stack of Tasks, this is null exactly when mFirst and mSecond are non-null. */
-    TaskStack mStack;
-
-    /** Content limits relative to the DisplayContent this sits in. */
-    Rect mBounds = new Rect();
-
-    /** Relative orientation of mFirst and mSecond. */
-    boolean mVertical;
-
-    /** Fraction of mBounds to devote to mFirst, remainder goes to mSecond */
-    float mWeight;
-
-    /** Dirty flag. Something inside this or some descendant of this has changed. */
-    boolean layoutNeeded;
-
-    /** True if this StackBox sits below the Status Bar. */
-    boolean mUnderStatusBar;
-
-    /** Used to keep from reallocating a temporary Rect for propagating bounds to child boxes */
-    Rect mTmpRect = new Rect();
-
-    StackBox(WindowManagerService service, DisplayContent displayContent, StackBox parent) {
-        synchronized (StackBox.class) {
-            mStackBoxId = sCurrentBoxId++;
-        }
-
-        mService = service;
-        mDisplayContent = displayContent;
-        mParent = parent;
-    }
-
-    /** Propagate #layoutNeeded bottom up. */
-    void makeDirty() {
-        layoutNeeded = true;
-        if (mParent != null) {
-            mParent.makeDirty();
-        }
-    }
-
-    /**
-     * Determine if a particular StackBox is this one or a descendant of this one.
-     * @param stackBoxId The StackBox being searched for.
-     * @return true if the specified StackBox matches this or one of its descendants.
-     */
-    boolean contains(int stackBoxId) {
-        return mStackBoxId == stackBoxId ||
-                (mStack == null &&  (mFirst.contains(stackBoxId) || mSecond.contains(stackBoxId)));
-    }
-
-    /**
-     * Return the stackId of the stack that intersects the passed point.
-     * @param x coordinate of point.
-     * @param y coordinate of point.
-     * @return -1 if point is outside of mBounds, otherwise the stackId of the containing stack.
-     */
-    int stackIdFromPoint(int x, int y) {
-        if (!mBounds.contains(x, y)) {
-            return -1;
-        }
-        if (mStack != null) {
-            return mStack.mStackId;
-        }
-        int stackId = mFirst.stackIdFromPoint(x, y);
-        if (stackId >= 0) {
-            return stackId;
-        }
-        return mSecond.stackIdFromPoint(x, y);
-    }
-
-    /** Determine if this StackBox is the first child or second child.
-     * @return true if this is the first child.
-     */
-    boolean isFirstChild() {
-        return mParent != null && mParent.mFirst == this;
-    }
-
-    /** Returns the bounds of the specified TaskStack if it is contained in this StackBox.
-     * @param stackId the TaskStack to find the bounds of.
-     * @return a new Rect with the bounds of stackId if it is within this StackBox, null otherwise.
-     */
-    Rect getStackBounds(int stackId) {
-        if (mStack != null) {
-            return mStack.mStackId == stackId ? new Rect(mBounds) : null;
-        }
-        Rect bounds = mFirst.getStackBounds(stackId);
-        if (bounds != null) {
-            return bounds;
-        }
-        return mSecond.getStackBounds(stackId);
-    }
-
-    /**
-     * Create a new TaskStack relative to a specified one by splitting the StackBox containing
-     * the specified TaskStack into two children. The size and position each of the new StackBoxes
-     * is determined by the passed parameters.
-     * @param stackId The id of the new TaskStack to create.
-     * @param relativeStackBoxId The id of the StackBox to place the new TaskStack next to.
-     * @param position One of the static TASK_STACK_GOES_xxx positions defined in this class.
-     * @param weight The percentage size of the parent StackBox to devote to the new TaskStack.
-     * @return The new TaskStack.
-     */
-    TaskStack split(int stackId, int relativeStackBoxId, int position, float weight) {
-        if (mStackBoxId != relativeStackBoxId) {
-            // This is not the targeted StackBox.
-            if (mStack != null) {
-                return null;
-            }
-            // Propagate the split to see if the targeted StackBox is in either sub box.
-            TaskStack stack = mFirst.split(stackId, relativeStackBoxId, position, weight);
-            if (stack != null) {
-                return stack;
-            }
-            return mSecond.split(stackId, relativeStackBoxId, position, weight);
-        }
-
-        // Found it!
-        TaskStack stack = new TaskStack(mService, stackId, mDisplayContent);
-        TaskStack firstStack;
-        TaskStack secondStack;
-        if (position == TASK_STACK_GOES_BEFORE) {
-            // TODO: Test Configuration here for LTR/RTL.
-            position = TASK_STACK_TO_LEFT_OF;
-        } else if (position == TASK_STACK_GOES_AFTER) {
-            // TODO: Test Configuration here for LTR/RTL.
-            position = TASK_STACK_TO_RIGHT_OF;
-        }
-        switch (position) {
-            default:
-            case TASK_STACK_TO_LEFT_OF:
-            case TASK_STACK_TO_RIGHT_OF:
-                mVertical = false;
-                if (position == TASK_STACK_TO_LEFT_OF) {
-                    mWeight = weight;
-                    firstStack = stack;
-                    secondStack = mStack;
-                } else {
-                    mWeight = 1.0f - weight;
-                    firstStack = mStack;
-                    secondStack = stack;
-                }
-                break;
-            case TASK_STACK_GOES_ABOVE:
-            case TASK_STACK_GOES_BELOW:
-                mVertical = true;
-                if (position == TASK_STACK_GOES_ABOVE) {
-                    mWeight = weight;
-                    firstStack = stack;
-                    secondStack = mStack;
-                } else {
-                    mWeight = 1.0f - weight;
-                    firstStack = mStack;
-                    secondStack = stack;
-                }
-                break;
-        }
-
-        mFirst = new StackBox(mService, mDisplayContent, this);
-        firstStack.mStackBox = mFirst;
-        mFirst.mStack = firstStack;
-
-        mSecond = new StackBox(mService, mDisplayContent, this);
-        secondStack.mStackBox = mSecond;
-        mSecond.mStack = secondStack;
-
-        mStack = null;
-        return stack;
-    }
-
-    /** Return the stackId of the first mFirst StackBox with a non-null mStack */
-    int getStackId() {
-        if (mStack != null) {
-            return mStack.mStackId;
-        }
-        return mFirst.getStackId();
-    }
-
-    /** Remove this box and propagate its sibling's content up to their parent.
-     * @return The first stackId of the resulting StackBox. */
-    int remove() {
-        mDisplayContent.layoutNeeded = true;
-
-        if (mParent == null) {
-            // This is the top-plane stack.
-            if (DEBUG_STACK) Slog.i(TAG, "StackBox.remove: removing top plane.");
-            mDisplayContent.removeStackBox(this);
-            return HOME_STACK_ID;
-        }
-
-        StackBox sibling = isFirstChild() ? mParent.mSecond : mParent.mFirst;
-        StackBox grandparent = mParent.mParent;
-        sibling.mParent = grandparent;
-        if (grandparent == null) {
-            // mParent is a top-plane stack. Now sibling will be.
-            if (DEBUG_STACK) Slog.i(TAG, "StackBox.remove: grandparent null");
-            mDisplayContent.removeStackBox(mParent);
-            mDisplayContent.addStackBox(sibling, true);
-        } else {
-            if (DEBUG_STACK) Slog.i(TAG, "StackBox.remove: grandparent getting sibling");
-            if (mParent.isFirstChild()) {
-                grandparent.mFirst = sibling;
-            } else {
-                grandparent.mSecond = sibling;
-            }
-        }
-        return sibling.getStackId();
-    }
-
-    boolean resize(int stackBoxId, float weight) {
-        if (mStackBoxId != stackBoxId) {
-            return mStack == null &&
-                    (mFirst.resize(stackBoxId, weight) || mSecond.resize(stackBoxId, weight));
-        }
-        // Don't change weight on topmost stack.
-        if (mParent != null) {
-            mParent.mWeight = isFirstChild() ? weight : 1.0f - weight;
-        }
-        return true;
-    }
-
-    /** If this is a terminal StackBox (contains a TaskStack) set the bounds.
-     * @param bounds The rectangle to set the bounds to.
-     * @param underStatusBar True if the StackBox is directly below the Status Bar.
-     * @return True if the bounds changed, false otherwise. */
-    boolean setStackBoxSizes(Rect bounds, boolean underStatusBar) {
-        boolean change = false;
-        if (mUnderStatusBar != underStatusBar) {
-            change = true;
-            mUnderStatusBar = underStatusBar;
-        }
-        if (mStack != null) {
-            change |= !mBounds.equals(bounds);
-            if (change) {
-                mBounds.set(bounds);
-                mStack.setBounds(bounds, underStatusBar);
-            }
-        } else {
-            mTmpRect.set(bounds);
-            if (mVertical) {
-                final int height = bounds.height();
-                int firstHeight = (int)(height * mWeight);
-                mTmpRect.bottom = bounds.top + firstHeight;
-                change |= mFirst.setStackBoxSizes(mTmpRect, underStatusBar);
-                mTmpRect.top = mTmpRect.bottom;
-                mTmpRect.bottom = bounds.top + height;
-                change |= mSecond.setStackBoxSizes(mTmpRect, false);
-            } else {
-                final int width = bounds.width();
-                int firstWidth = (int)(width * mWeight);
-                mTmpRect.right = bounds.left + firstWidth;
-                change |= mFirst.setStackBoxSizes(mTmpRect, underStatusBar);
-                mTmpRect.left = mTmpRect.right;
-                mTmpRect.right = bounds.left + width;
-                change |= mSecond.setStackBoxSizes(mTmpRect, underStatusBar);
-            }
-        }
-        return change;
-    }
-
-    void resetAnimationBackgroundAnimator() {
-        if (mStack != null) {
-            mStack.resetAnimationBackgroundAnimator();
-            return;
-        }
-        mFirst.resetAnimationBackgroundAnimator();
-        mSecond.resetAnimationBackgroundAnimator();
-    }
-
-    boolean animateDimLayers() {
-        if (mStack != null) {
-            return mStack.animateDimLayers();
-        }
-        boolean result = mFirst.animateDimLayers();
-        result |= mSecond.animateDimLayers();
-        return result;
-    }
-
-    void resetDimming() {
-        if (mStack != null) {
-            mStack.resetDimmingTag();
-            return;
-        }
-        mFirst.resetDimming();
-        mSecond.resetDimming();
-    }
-
-    boolean isDimming() {
-        if (mStack != null) {
-            return mStack.isDimming();
-        }
-        boolean result = mFirst.isDimming();
-        result |= mSecond.isDimming();
-        return result;
-    }
-
-    void stopDimmingIfNeeded() {
-        if (mStack != null) {
-            mStack.stopDimmingIfNeeded();
-            return;
-        }
-        mFirst.stopDimmingIfNeeded();
-        mSecond.stopDimmingIfNeeded();
-    }
-
-    void switchUserStacks(int userId) {
-        if (mStack != null) {
-            mStack.switchUser(userId);
-            return;
-        }
-        mFirst.switchUserStacks(userId);
-        mSecond.switchUserStacks(userId);
-    }
-
-    void close() {
-        if (mStack != null) {
-            mStack.mDimLayer.mDimSurface.destroy();
-            mStack.mAnimationBackgroundSurface.mDimSurface.destroy();
-            return;
-        }
-        mFirst.close();
-        mSecond.close();
-    }
-
-    public void dump(String prefix, PrintWriter pw) {
-        pw.print(prefix); pw.print("mParent="); pw.println(mParent);
-        pw.print(prefix); pw.print("mBounds="); pw.print(mBounds.toShortString());
-            pw.print(" mVertical="); pw.print(mVertical);
-            pw.print(" layoutNeeded="); pw.println(layoutNeeded);
-        if (mFirst != null) {
-            pw.print(prefix); pw.print("mFirst="); pw.println(System.identityHashCode(mFirst));
-            mFirst.dump(prefix + "  ", pw);
-            pw.print(prefix); pw.print("mSecond="); pw.println(System.identityHashCode(mSecond));
-            mSecond.dump(prefix + "  ", pw);
-        } else {
-            pw.print(prefix); pw.print("mStack="); pw.println(mStack);
-            mStack.dump(prefix + "  ", pw);
-        }
-    }
-
-    @Override
-    public String toString() {
-        if (mStack != null) {
-            return "Box{" + hashCode() + " stack=" + mStack.mStackId + "}";
-        }
-        return "Box{" + hashCode() + " parent=" + System.identityHashCode(mParent)
-                + " first=" + System.identityHashCode(mFirst)
-                + " second=" + System.identityHashCode(mSecond) + "}";
-    }
-}
diff --git a/services/jni/Android.mk b/services/jni/Android.mk
deleted file mode 100644
index 98e9b30..0000000
--- a/services/jni/Android.mk
+++ /dev/null
@@ -1,63 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-    com_android_server_AlarmManagerService.cpp \
-    com_android_server_AssetAtlasService.cpp \
-    com_android_server_ConsumerIrService.cpp \
-    com_android_server_input_InputApplicationHandle.cpp \
-    com_android_server_input_InputManagerService.cpp \
-    com_android_server_input_InputWindowHandle.cpp \
-    com_android_server_LightsService.cpp \
-    com_android_server_power_PowerManagerService.cpp \
-    com_android_server_SerialService.cpp \
-    com_android_server_SystemServer.cpp \
-    com_android_server_UsbDeviceManager.cpp \
-    com_android_server_UsbHostManager.cpp \
-    com_android_server_VibratorService.cpp \
-    com_android_server_location_GpsLocationProvider.cpp \
-    com_android_server_location_FlpHardwareProvider.cpp \
-    com_android_server_connectivity_Vpn.cpp \
-    onload.cpp
-
-LOCAL_C_INCLUDES += \
-    $(JNI_H_INCLUDE) \
-    frameworks/base/services \
-    frameworks/base/core/jni \
-    frameworks/native/services \
-    external/skia/include/core \
-    libcore/include \
-    libcore/include/libsuspend \
-	$(call include-path-for, libhardware)/hardware \
-	$(call include-path-for, libhardware_legacy)/hardware_legacy \
-
-LOCAL_SHARED_LIBRARIES := \
-    libandroid_runtime \
-    libandroidfw \
-    libbinder \
-    libcutils \
-    liblog \
-    libhardware \
-    libhardware_legacy \
-    libnativehelper \
-    libutils \
-    libui \
-    libinput \
-    libinputservice \
-    libsensorservice \
-    libskia \
-    libgui \
-    libusbhost \
-    libsuspend \
-    libEGL \
-    libGLESv2
-
-LOCAL_CFLAGS += -DEGL_EGLEXT_PROTOTYPES -DGL_GLEXT_PROTOTYPES
-
-ifeq ($(WITH_MALLOC_LEAK_CHECK),true)
-    LOCAL_CFLAGS += -DMALLOC_LEAK_CHECK
-endif
-
-LOCAL_MODULE:= libandroid_servers
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/services/print/Android.mk b/services/print/Android.mk
new file mode 100644
index 0000000..33604b7
--- /dev/null
+++ b/services/print/Android.mk
@@ -0,0 +1,10 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := services.print
+
+LOCAL_SRC_FILES += \
+      $(call all-java-files-under,java)
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/services/print/java/com/android/server/print/PrintManagerService.java b/services/print/java/com/android/server/print/PrintManagerService.java
new file mode 100644
index 0000000..c6fdbe5
--- /dev/null
+++ b/services/print/java/com/android/server/print/PrintManagerService.java
@@ -0,0 +1,689 @@
+/*
+ * 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.print;
+
+import android.Manifest;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+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.database.ContentObserver;
+import android.net.Uri;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.print.IPrintDocumentAdapter;
+import android.print.IPrintJobStateChangeListener;
+import android.print.IPrintManager;
+import android.print.IPrinterDiscoveryObserver;
+import android.print.PrintAttributes;
+import android.print.PrintJobId;
+import android.print.PrintJobInfo;
+import android.print.PrinterId;
+import android.printservice.PrintServiceInfo;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.SparseArray;
+
+import com.android.internal.R;
+import com.android.internal.content.PackageMonitor;
+import com.android.internal.os.BackgroundThread;
+import com.android.server.SystemService;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * SystemService wrapper for the PrintManager implementation. Publishes
+ * Context.PRINT_SERVICE.
+ * PrintManager implementation is contained within.
+ */
+
+public final class PrintManagerService extends SystemService {
+    private final PrintManagerImpl mPrintManagerImpl;
+
+    public PrintManagerService(Context context) {
+        super(context);
+        mPrintManagerImpl = new PrintManagerImpl(context);
+    }
+
+    @Override
+    public void onStart() {
+        publishBinderService(Context.PRINT_SERVICE, mPrintManagerImpl);
+    }
+
+    @Override
+    public void onBootPhase(int phase) {
+        if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
+            mPrintManagerImpl.systemRunning();
+        }
+    }
+
+    class PrintManagerImpl extends IPrintManager.Stub {
+        private static final char COMPONENT_NAME_SEPARATOR = ':';
+
+        private static final String EXTRA_PRINT_SERVICE_COMPONENT_NAME =
+                "EXTRA_PRINT_SERVICE_COMPONENT_NAME";
+
+        private final Object mLock = new Object();
+
+        private final Context mContext;
+
+        private final SparseArray<UserState> mUserStates = new SparseArray<UserState>();
+
+        private int mCurrentUserId = UserHandle.USER_OWNER;
+
+        PrintManagerImpl(Context context) {
+            mContext = context;
+            registerContentObservers();
+            registerBoradcastReceivers();
+        }
+
+        public void systemRunning() {
+            BackgroundThread.getHandler().post(new Runnable() {
+                @Override
+                public void run() {
+                    final UserState userState;
+                    synchronized (mLock) {
+                        userState = getCurrentUserStateLocked();
+                        userState.updateIfNeededLocked();
+                    }
+                    // This is the first time we switch to this user after boot, so
+                    // now is the time to remove obsolete print jobs since they
+                    // are from the last boot and no application would query them.
+                    userState.removeObsoletePrintJobs();
+                }
+            });
+        }
+
+        @Override
+        public Bundle print(String printJobName, IPrintDocumentAdapter adapter,
+                PrintAttributes attributes, String packageName, int appId, int userId) {
+            final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
+            final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+            String resolvedPackageName = resolveCallingPackageNameEnforcingSecurity(packageName);
+            final UserState userState;
+            synchronized (mLock) {
+                userState = getOrCreateUserStateLocked(resolvedUserId);
+            }
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                return userState.print(printJobName, adapter, attributes,
+                        resolvedPackageName, resolvedAppId);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
+        public List<PrintJobInfo> getPrintJobInfos(int appId, int userId) {
+            final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
+            final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+            final UserState userState;
+            synchronized (mLock) {
+                userState = getOrCreateUserStateLocked(resolvedUserId);
+            }
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                return userState.getPrintJobInfos(resolvedAppId);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
+        public PrintJobInfo getPrintJobInfo(PrintJobId printJobId, int appId, int userId) {
+            final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
+            final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+            final UserState userState;
+            synchronized (mLock) {
+                userState = getOrCreateUserStateLocked(resolvedUserId);
+            }
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                return userState.getPrintJobInfo(printJobId, resolvedAppId);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
+        public void cancelPrintJob(PrintJobId printJobId, int appId, int userId) {
+            final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
+            final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+            final UserState userState;
+            synchronized (mLock) {
+                userState = getOrCreateUserStateLocked(resolvedUserId);
+            }
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                userState.cancelPrintJob(printJobId, resolvedAppId);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
+        public void restartPrintJob(PrintJobId printJobId, int appId, int userId) {
+            final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
+            final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+            final UserState userState;
+            synchronized (mLock) {
+                userState = getOrCreateUserStateLocked(resolvedUserId);
+            }
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                userState.restartPrintJob(printJobId, resolvedAppId);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
+        public List<PrintServiceInfo> getEnabledPrintServices(int userId) {
+            final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+            final UserState userState;
+            synchronized (mLock) {
+                userState = getOrCreateUserStateLocked(resolvedUserId);
+            }
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                return userState.getEnabledPrintServices();
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
+        public List<PrintServiceInfo> getInstalledPrintServices(int userId) {
+            final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+            final UserState userState;
+            synchronized (mLock) {
+                userState = getOrCreateUserStateLocked(resolvedUserId);
+            }
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                return userState.getInstalledPrintServices();
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
+        public void createPrinterDiscoverySession(IPrinterDiscoveryObserver observer,
+                int userId) {
+            final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+            final UserState userState;
+            synchronized (mLock) {
+                userState = getOrCreateUserStateLocked(resolvedUserId);
+            }
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                userState.createPrinterDiscoverySession(observer);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
+        public void destroyPrinterDiscoverySession(IPrinterDiscoveryObserver observer,
+                int userId) {
+            final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+            final UserState userState;
+            synchronized (mLock) {
+                userState = getOrCreateUserStateLocked(resolvedUserId);
+            }
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                userState.destroyPrinterDiscoverySession(observer);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
+        public void startPrinterDiscovery(IPrinterDiscoveryObserver observer,
+                List<PrinterId> priorityList, int userId) {
+            final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+            final UserState userState;
+            synchronized (mLock) {
+                userState = getOrCreateUserStateLocked(resolvedUserId);
+            }
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                userState.startPrinterDiscovery(observer, priorityList);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
+        public void stopPrinterDiscovery(IPrinterDiscoveryObserver observer, int userId) {
+            final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+            final UserState userState;
+            synchronized (mLock) {
+                userState = getOrCreateUserStateLocked(resolvedUserId);
+            }
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                userState.stopPrinterDiscovery(observer);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
+        public void validatePrinters(List<PrinterId> printerIds, int userId) {
+            final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+            final UserState userState;
+            synchronized (mLock) {
+                userState = getOrCreateUserStateLocked(resolvedUserId);
+            }
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                userState.validatePrinters(printerIds);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
+        public void startPrinterStateTracking(PrinterId printerId, int userId) {
+            final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+            final UserState userState;
+            synchronized (mLock) {
+                userState = getOrCreateUserStateLocked(resolvedUserId);
+            }
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                userState.startPrinterStateTracking(printerId);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
+        public void stopPrinterStateTracking(PrinterId printerId, int userId) {
+            final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+            final UserState userState;
+            synchronized (mLock) {
+                userState = getOrCreateUserStateLocked(resolvedUserId);
+            }
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                userState.stopPrinterStateTracking(printerId);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
+        public void addPrintJobStateChangeListener(IPrintJobStateChangeListener listener,
+                int appId, int userId) throws RemoteException {
+            final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+            final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
+            final UserState userState;
+            synchronized (mLock) {
+                userState = getOrCreateUserStateLocked(resolvedUserId);
+            }
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                userState.addPrintJobStateChangeListener(listener, resolvedAppId);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
+        public void removePrintJobStateChangeListener(IPrintJobStateChangeListener listener,
+                int userId) {
+            final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+            final UserState userState;
+            synchronized (mLock) {
+                userState = getOrCreateUserStateLocked(resolvedUserId);
+            }
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                userState.removePrintJobStateChangeListener(listener);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
+        public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+            if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP)
+                    != PackageManager.PERMISSION_GRANTED) {
+                pw.println("Permission Denial: can't dump PrintManager from from pid="
+                        + Binder.getCallingPid()
+                        + ", uid=" + Binder.getCallingUid());
+                return;
+            }
+
+            synchronized (mLock) {
+                final long identity = Binder.clearCallingIdentity();
+                try {
+                    pw.println("PRINT MANAGER STATE (dumpsys print)");
+                    final int userStateCount = mUserStates.size();
+                    for (int i = 0; i < userStateCount; i++) {
+                        UserState userState = mUserStates.valueAt(i);
+                        userState.dump(fd, pw, "");
+                        pw.println();
+                    }
+                } finally {
+                    Binder.restoreCallingIdentity(identity);
+                }
+            }
+        }
+
+        private void registerContentObservers() {
+            final Uri enabledPrintServicesUri = Settings.Secure.getUriFor(
+                    Settings.Secure.ENABLED_PRINT_SERVICES);
+
+            ContentObserver observer = new ContentObserver(BackgroundThread.getHandler()) {
+                @Override
+                public void onChange(boolean selfChange, Uri uri) {
+                    if (enabledPrintServicesUri.equals(uri)) {
+                        synchronized (mLock) {
+                            UserState userState = getCurrentUserStateLocked();
+                            userState.updateIfNeededLocked();
+                        }
+                    }
+                }
+            };
+
+            mContext.getContentResolver().registerContentObserver(enabledPrintServicesUri,
+                    false, observer, UserHandle.USER_ALL);
+        }
+
+        private void registerBoradcastReceivers() {
+            PackageMonitor monitor = new PackageMonitor() {
+                @Override
+                public boolean onPackageChanged(String packageName, int uid, String[] components) {
+                    synchronized (mLock) {
+                        UserState userState = getOrCreateUserStateLocked(getChangingUserId());
+                        Iterator<ComponentName> iterator = userState.getEnabledServices()
+                                .iterator();
+                        while (iterator.hasNext()) {
+                            ComponentName componentName = iterator.next();
+                            if (packageName.equals(componentName.getPackageName())) {
+                                userState.updateIfNeededLocked();
+                                return true;
+                            }
+                        }
+                    }
+                    return false;
+                }
+
+                @Override
+                public void onPackageRemoved(String packageName, int uid) {
+                    synchronized (mLock) {
+                        UserState userState = getOrCreateUserStateLocked(getChangingUserId());
+                        Iterator<ComponentName> iterator = userState.getEnabledServices()
+                                .iterator();
+                        while (iterator.hasNext()) {
+                            ComponentName componentName = iterator.next();
+                            if (packageName.equals(componentName.getPackageName())) {
+                                iterator.remove();
+                                persistComponentNamesToSettingLocked(
+                                        Settings.Secure.ENABLED_PRINT_SERVICES,
+                                        userState.getEnabledServices(), getChangingUserId());
+                                userState.updateIfNeededLocked();
+                                return;
+                            }
+                        }
+                    }
+                }
+
+                @Override
+                public boolean onHandleForceStop(Intent intent, String[] stoppedPackages,
+                        int uid, boolean doit) {
+                    synchronized (mLock) {
+                        UserState userState = getOrCreateUserStateLocked(getChangingUserId());
+                        boolean stoppedSomePackages = false;
+                        Iterator<ComponentName> iterator = userState.getEnabledServices()
+                                .iterator();
+                        while (iterator.hasNext()) {
+                            ComponentName componentName = iterator.next();
+                            String componentPackage = componentName.getPackageName();
+                            for (String stoppedPackage : stoppedPackages) {
+                                if (componentPackage.equals(stoppedPackage)) {
+                                    if (!doit) {
+                                        return true;
+                                    }
+                                    stoppedSomePackages = true;
+                                    break;
+                                }
+                            }
+                        }
+                        if (stoppedSomePackages) {
+                            userState.updateIfNeededLocked();
+                        }
+                        return false;
+                    }
+                }
+
+                @Override
+                public void onPackageAdded(String packageName, int uid) {
+                    Intent intent = new Intent(android.printservice.PrintService.SERVICE_INTERFACE);
+                    intent.setPackage(packageName);
+
+                    List<ResolveInfo> installedServices = mContext.getPackageManager()
+                            .queryIntentServicesAsUser(intent, PackageManager.GET_SERVICES,
+                                    getChangingUserId());
+
+                    if (installedServices == null) {
+                        return;
+                    }
+
+                    final int installedServiceCount = installedServices.size();
+                    for (int i = 0; i < installedServiceCount; i++) {
+                        ServiceInfo serviceInfo = installedServices.get(i).serviceInfo;
+                        ComponentName component = new ComponentName(serviceInfo.packageName,
+                                serviceInfo.name);
+                        String label = serviceInfo.loadLabel(mContext.getPackageManager())
+                                .toString();
+                        showEnableInstalledPrintServiceNotification(component, label,
+                                getChangingUserId());
+                    }
+                }
+
+                private void persistComponentNamesToSettingLocked(String settingName,
+                        Set<ComponentName> componentNames, int userId) {
+                    StringBuilder builder = new StringBuilder();
+                    for (ComponentName componentName : componentNames) {
+                        if (builder.length() > 0) {
+                            builder.append(COMPONENT_NAME_SEPARATOR);
+                        }
+                        builder.append(componentName.flattenToShortString());
+                    }
+                    Settings.Secure.putStringForUser(mContext.getContentResolver(),
+                            settingName, builder.toString(), userId);
+                }
+            };
+
+            // package changes
+            monitor.register(mContext, BackgroundThread.getHandler().getLooper(),
+                    UserHandle.ALL, true);
+
+            // user changes
+            IntentFilter intentFilter = new IntentFilter();
+            intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
+            intentFilter.addAction(Intent.ACTION_USER_REMOVED);
+
+            mContext.registerReceiverAsUser(new BroadcastReceiver() {
+                @Override
+                public void onReceive(Context context, Intent intent) {
+                    String action = intent.getAction();
+                    if (Intent.ACTION_USER_SWITCHED.equals(action)) {
+                        switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
+                    } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
+                        removeUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
+                    }
+                }
+            }, UserHandle.ALL, intentFilter, null, BackgroundThread.getHandler());
+        }
+
+        private UserState getCurrentUserStateLocked() {
+            return getOrCreateUserStateLocked(mCurrentUserId);
+        }
+
+        private UserState getOrCreateUserStateLocked(int userId) {
+            UserState userState = mUserStates.get(userId);
+            if (userState == null) {
+                userState = new UserState(mContext, userId, mLock);
+                mUserStates.put(userId, userState);
+            }
+            return userState;
+        }
+
+        private void switchUser(int newUserId) {
+            UserState userState;
+            synchronized (mLock) {
+                if (newUserId == mCurrentUserId) {
+                    return;
+                }
+                mCurrentUserId = newUserId;
+                userState = mUserStates.get(mCurrentUserId);
+                if (userState == null) {
+                    userState = getCurrentUserStateLocked();
+                    userState.updateIfNeededLocked();
+                } else {
+                    userState.updateIfNeededLocked();
+                }
+            }
+            // This is the first time we switch to this user after boot, so
+            // now is the time to remove obsolete print jobs since they
+            // are from the last boot and no application would query them.
+            userState.removeObsoletePrintJobs();
+        }
+
+        private void removeUser(int removedUserId) {
+            synchronized (mLock) {
+                UserState userState = mUserStates.get(removedUserId);
+                if (userState != null) {
+                    userState.destroyLocked();
+                    mUserStates.remove(removedUserId);
+                }
+            }
+        }
+
+        private int resolveCallingAppEnforcingPermissions(int appId) {
+            final int callingUid = Binder.getCallingUid();
+            if (callingUid == 0 || callingUid == Process.SYSTEM_UID
+                    || callingUid == Process.SHELL_UID) {
+                return appId;
+            }
+            final int callingAppId = UserHandle.getAppId(callingUid);
+            if (appId == callingAppId) {
+                return appId;
+            }
+            if (mContext.checkCallingPermission(
+                    "com.android.printspooler.permission.ACCESS_ALL_PRINT_JOBS")
+                    != PackageManager.PERMISSION_GRANTED) {
+                throw new SecurityException("Call from app " + callingAppId + " as app "
+                        + appId + " without com.android.printspooler.permission"
+                        + ".ACCESS_ALL_PRINT_JOBS");
+            }
+            return appId;
+        }
+
+        private int resolveCallingUserEnforcingPermissions(int userId) {
+            final int callingUid = Binder.getCallingUid();
+            if (callingUid == 0 || callingUid == Process.SYSTEM_UID
+                    || callingUid == Process.SHELL_UID) {
+                return userId;
+            }
+            final int callingUserId = UserHandle.getUserId(callingUid);
+            if (callingUserId == userId) {
+                return userId;
+            }
+            if (mContext.checkCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL)
+                    != PackageManager.PERMISSION_GRANTED
+                ||  mContext.checkCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS)
+                    != PackageManager.PERMISSION_GRANTED) {
+                if (userId == UserHandle.USER_CURRENT_OR_SELF) {
+                    return callingUserId;
+                }
+                throw new SecurityException("Call from user " + callingUserId + " as user "
+                    + userId + " without permission INTERACT_ACROSS_USERS or "
+                    + "INTERACT_ACROSS_USERS_FULL not allowed.");
+            }
+            if (userId == UserHandle.USER_CURRENT || userId == UserHandle.USER_CURRENT_OR_SELF) {
+                return mCurrentUserId;
+            }
+            throw new IllegalArgumentException("Calling user can be changed to only "
+                    + "UserHandle.USER_CURRENT or UserHandle.USER_CURRENT_OR_SELF.");
+        }
+
+        private String resolveCallingPackageNameEnforcingSecurity(String packageName) {
+            if (TextUtils.isEmpty(packageName)) {
+                return null;
+            }
+            String[] packages = mContext.getPackageManager().getPackagesForUid(
+                    Binder.getCallingUid());
+            final int packageCount = packages.length;
+            for (int i = 0; i < packageCount; i++) {
+                if (packageName.equals(packages[i])) {
+                    return packageName;
+                }
+            }
+            return null;
+        }
+
+        private void showEnableInstalledPrintServiceNotification(ComponentName component,
+                String label, int userId) {
+            UserHandle userHandle = new UserHandle(userId);
+
+            Intent intent = new Intent(Settings.ACTION_PRINT_SETTINGS);
+            intent.putExtra(EXTRA_PRINT_SERVICE_COMPONENT_NAME, component.flattenToString());
+
+            PendingIntent pendingIntent = PendingIntent.getActivityAsUser(mContext, 0, intent,
+                    PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_CANCEL_CURRENT, null,
+                    userHandle);
+
+            Notification.Builder builder = new Notification.Builder(mContext)
+                    .setSmallIcon(R.drawable.ic_print)
+                    .setContentTitle(mContext.getString(R.string.print_service_installed_title,
+                            label))
+                    .setContentText(mContext.getString(R.string.print_service_installed_message))
+                    .setContentIntent(pendingIntent)
+                    .setWhen(System.currentTimeMillis())
+                    .setAutoCancel(true)
+                    .setShowWhen(true);
+
+            NotificationManager notificationManager = (NotificationManager) mContext
+                    .getSystemService(Context.NOTIFICATION_SERVICE);
+
+            String notificationTag = getClass().getName() + ":" + component.flattenToString();
+            notificationManager.notifyAsUser(notificationTag, 0, builder.build(),
+                    userHandle);
+        }
+    }
+}
diff --git a/services/java/com/android/server/print/RemotePrintService.java b/services/print/java/com/android/server/print/RemotePrintService.java
similarity index 100%
rename from services/java/com/android/server/print/RemotePrintService.java
rename to services/print/java/com/android/server/print/RemotePrintService.java
diff --git a/services/java/com/android/server/print/RemotePrintSpooler.java b/services/print/java/com/android/server/print/RemotePrintSpooler.java
similarity index 100%
rename from services/java/com/android/server/print/RemotePrintSpooler.java
rename to services/print/java/com/android/server/print/RemotePrintSpooler.java
diff --git a/services/java/com/android/server/print/UserState.java b/services/print/java/com/android/server/print/UserState.java
similarity index 100%
rename from services/java/com/android/server/print/UserState.java
rename to services/print/java/com/android/server/print/UserState.java
diff --git a/services/tests/Android.mk b/services/tests/Android.mk
new file mode 100644
index 0000000..40369ee
--- /dev/null
+++ b/services/tests/Android.mk
@@ -0,0 +1,3 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(call all-makefiles-under, $(LOCAL_PATH))
diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
index 8b9f718..8392672 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
@@ -216,7 +216,7 @@
         expectLastCall().atLeastOnce();
 
         // expect to answer screen status during systemReady()
-        expect(mPowerManager.isScreenOn()).andReturn(true).atLeastOnce();
+        expect(mPowerManager.isInteractive()).andReturn(true).atLeastOnce();
         expect(mNetworkManager.isBandwidthControlEnabled()).andReturn(true).atLeastOnce();
         expectCurrentTime();
 
@@ -331,7 +331,7 @@
         verifyAndReset();
 
         // now turn screen off and verify REJECT rule
-        expect(mPowerManager.isScreenOn()).andReturn(false).atLeastOnce();
+        expect(mPowerManager.isInteractive()).andReturn(false).atLeastOnce();
         expectSetUidNetworkRules(UID_A, true);
         expectSetUidForeground(UID_A, false);
         future = expectRulesChanged(UID_A, RULE_REJECT_METERED);
@@ -341,7 +341,7 @@
         verifyAndReset();
 
         // and turn screen back on, verify ALLOW rule restored
-        expect(mPowerManager.isScreenOn()).andReturn(true).atLeastOnce();
+        expect(mPowerManager.isInteractive()).andReturn(true).atLeastOnce();
         expectSetUidNetworkRules(UID_A, false);
         expectSetUidForeground(UID_A, true);
         future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
diff --git a/services/usb/Android.mk b/services/usb/Android.mk
new file mode 100644
index 0000000..feabf0a
--- /dev/null
+++ b/services/usb/Android.mk
@@ -0,0 +1,12 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := services.usb
+
+LOCAL_SRC_FILES += \
+      $(call all-java-files-under,java)
+
+LOCAL_JAVA_LIBRARIES := services.core
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/services/java/com/android/server/usb/UsbDebuggingManager.java b/services/usb/java/com/android/server/usb/UsbDebuggingManager.java
similarity index 80%
rename from services/java/com/android/server/usb/UsbDebuggingManager.java
rename to services/usb/java/com/android/server/usb/UsbDebuggingManager.java
index ce953a4..0946c5a 100644
--- a/services/java/com/android/server/usb/UsbDebuggingManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDebuggingManager.java
@@ -17,8 +17,12 @@
 package com.android.server.usb;
 
 import android.content.ActivityNotFoundException;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
 import android.net.LocalSocket;
 import android.net.LocalSocketAddress;
 import android.os.Handler;
@@ -208,7 +212,7 @@
                 case MESSAGE_ADB_CONFIRM: {
                     String key = (String)msg.obj;
                     mFingerprints = getFingerprints(key);
-                    showConfirmationDialog(key, mFingerprints);
+                    startConfirmation(key, mFingerprints);
                     break;
                 }
 
@@ -243,19 +247,60 @@
         return sb.toString();
     }
 
-    private void showConfirmationDialog(String key, String fingerprints) {
-        Intent dialogIntent = new Intent();
-
-        dialogIntent.setClassName("com.android.systemui",
-                "com.android.systemui.usb.UsbDebuggingActivity");
-        dialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        dialogIntent.putExtra("key", key);
-        dialogIntent.putExtra("fingerprints", fingerprints);
-        try {
-            mContext.startActivity(dialogIntent);
-        } catch (ActivityNotFoundException e) {
-            Slog.e(TAG, "unable to start UsbDebuggingActivity");
+    private void startConfirmation(String key, String fingerprints) {
+        String nameString = Resources.getSystem().getString(
+                com.android.internal.R.string.config_customAdbPublicKeyConfirmationComponent);
+        ComponentName componentName = ComponentName.unflattenFromString(nameString);
+        if (startConfirmationActivity(componentName, key, fingerprints)
+                || startConfirmationService(componentName, key, fingerprints)) {
+            return;
         }
+        Slog.e(TAG, "unable to start customAdbPublicKeyConfirmationComponent "
+                + nameString + " as an Activity or a Service");
+    }
+
+    /**
+     * @returns true if the componentName led to an Activity that was started.
+     */
+    private boolean startConfirmationActivity(ComponentName componentName, String key,
+            String fingerprints) {
+        PackageManager packageManager = mContext.getPackageManager();
+        Intent intent = createConfirmationIntent(componentName, key, fingerprints);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        if (packageManager.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY) != null) {
+            try {
+                mContext.startActivity(intent);
+                return true;
+            } catch (ActivityNotFoundException e) {
+                Slog.e(TAG, "unable to start adb whitelist activity: " + componentName, e);
+            }
+        }
+        return false;
+    }
+
+    /**
+     * @returns true if the componentName led to a Service that was started.
+     */
+    private boolean startConfirmationService(ComponentName componentName, String key,
+            String fingerprints) {
+        Intent intent = createConfirmationIntent(componentName, key, fingerprints);
+        try {
+            if (mContext.startService(intent) != null) {
+                return true;
+            }
+        } catch (SecurityException e) {
+            Slog.e(TAG, "unable to start adb whitelist service: " + componentName, e);
+        }
+        return false;
+    }
+
+    private Intent createConfirmationIntent(ComponentName componentName, String key,
+            String fingerprints) {
+        Intent intent = new Intent();
+        intent.setClassName(componentName.getPackageName(), componentName.getClassName());
+        intent.putExtra("key", key);
+        intent.putExtra("fingerprints", fingerprints);
+        return intent;
     }
 
     private File getUserKeyFile() {
diff --git a/services/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
similarity index 99%
rename from services/java/com/android/server/usb/UsbDeviceManager.java
rename to services/usb/java/com/android/server/usb/UsbDeviceManager.java
index b932632..5d22ffc 100644
--- a/services/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -836,7 +836,7 @@
                     if (mOemModeMap == null) {
                         mOemModeMap = new HashMap<String, List<Pair<String, String>>>();
                     }
-                    List overrideList = mOemModeMap.get(items[0]);
+                    List<Pair<String, String>> overrideList = mOemModeMap.get(items[0]);
                     if (overrideList == null) {
                         overrideList = new LinkedList<Pair<String, String>>();
                         mOemModeMap.put(items[0], overrideList);
diff --git a/services/java/com/android/server/usb/UsbHostManager.java b/services/usb/java/com/android/server/usb/UsbHostManager.java
similarity index 100%
rename from services/java/com/android/server/usb/UsbHostManager.java
rename to services/usb/java/com/android/server/usb/UsbHostManager.java
diff --git a/services/java/com/android/server/usb/UsbService.java b/services/usb/java/com/android/server/usb/UsbService.java
similarity index 94%
rename from services/java/com/android/server/usb/UsbService.java
rename to services/usb/java/com/android/server/usb/UsbService.java
index 36669b1..b6ae192 100644
--- a/services/java/com/android/server/usb/UsbService.java
+++ b/services/usb/java/com/android/server/usb/UsbService.java
@@ -32,6 +32,7 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.SystemService;
 
 import java.io.File;
 import java.io.FileDescriptor;
@@ -43,6 +44,28 @@
  * support is delegated to UsbDeviceManager.
  */
 public class UsbService extends IUsbManager.Stub {
+
+    public static class Lifecycle extends SystemService {
+        private UsbService mUsbService;
+
+        public Lifecycle(Context context) {
+            super(context);
+        }
+
+        @Override
+        public void onStart() {
+            mUsbService = new UsbService(getContext());
+            publishBinderService(Context.USB_SERVICE, mUsbService);
+        }
+
+        @Override
+        public void onBootPhase(int phase) {
+            if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
+                mUsbService.systemReady();
+            }
+        }
+    }
+
     private static final String TAG = "UsbService";
 
     private final Context mContext;
diff --git a/services/java/com/android/server/usb/UsbSettingsManager.java b/services/usb/java/com/android/server/usb/UsbSettingsManager.java
similarity index 100%
rename from services/java/com/android/server/usb/UsbSettingsManager.java
rename to services/usb/java/com/android/server/usb/UsbSettingsManager.java
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index 661bd41..a6b817e 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -79,7 +79,14 @@
         throw new UnsupportedOperationException();
     }
 
+    /** @hide */
     @Override
+    public Intent getLeanbackLaunchIntentForPackage(String packageName) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+
     public int[] getPackageGids(String packageName) throws NameNotFoundException {
         throw new UnsupportedOperationException();
     }
@@ -338,6 +345,27 @@
     }
 
     @Override
+    public Drawable getActivityBanner(ComponentName activityName)
+            throws NameNotFoundException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Drawable getActivityBanner(Intent intent) throws NameNotFoundException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Drawable getApplicationBanner(ApplicationInfo info) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Drawable getApplicationBanner(String packageName) throws NameNotFoundException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
     public Drawable getApplicationIcon(ApplicationInfo info) {
         throw new UnsupportedOperationException();
     }
diff --git a/tests/CoreTests/android/core/NsdServiceInfoTest.java b/tests/CoreTests/android/core/NsdServiceInfoTest.java
new file mode 100644
index 0000000..5bf0167
--- /dev/null
+++ b/tests/CoreTests/android/core/NsdServiceInfoTest.java
@@ -0,0 +1,163 @@
+package android.core;
+
+import android.test.AndroidTestCase;
+
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.StrictMode;
+import android.net.nsd.NsdServiceInfo;
+import android.util.Log;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+
+public class NsdServiceInfoTest extends AndroidTestCase {
+
+    public final static InetAddress LOCALHOST;
+    static {
+        // Because test.
+        StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
+        StrictMode.setThreadPolicy(policy);
+
+        InetAddress _host = null;
+        try {
+            _host = InetAddress.getLocalHost();
+        } catch (UnknownHostException e) { }
+        LOCALHOST = _host;
+    }
+
+    public void testLimits() throws Exception {
+        NsdServiceInfo info = new NsdServiceInfo();
+
+        // Non-ASCII keys.
+        boolean exceptionThrown = false;
+        try {
+            info.setAttribute("猫", "meow");
+        } catch (IllegalArgumentException e) {
+            exceptionThrown = true;
+        }
+        assertTrue(exceptionThrown);
+        assertEmptyServiceInfo(info);
+
+        // ASCII keys with '=' character.
+        exceptionThrown = false;
+        try {
+            info.setAttribute("kitten=", "meow");
+        } catch (IllegalArgumentException e) {
+            exceptionThrown = true;
+        }
+        assertTrue(exceptionThrown);
+        assertEmptyServiceInfo(info);
+
+        // Single key + value length too long.
+        exceptionThrown = false;
+        try {
+            String longValue = "loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo" +
+                    "oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo" +
+                    "oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo" +
+                    "ooooooooooooooooooooooooooooong";  // 248 characters.
+            info.setAttribute("longcat", longValue);  // Key + value == 255 characters.
+        } catch (IllegalArgumentException e) {
+            exceptionThrown = true;
+        }
+        assertTrue(exceptionThrown);
+        assertEmptyServiceInfo(info);
+
+        // Total TXT record length too long.
+        exceptionThrown = false;
+        int recordsAdded = 0;
+        try {
+            for (int i = 100; i < 300; ++i) {
+                // 6 char key + 5 char value + 2 bytes overhead = 13 byte record length.
+                String key = String.format("key%d", i);
+                info.setAttribute(key, "12345");
+                recordsAdded++;
+            }
+        } catch (IllegalArgumentException e) {
+            exceptionThrown = true;
+        }
+        assertTrue(exceptionThrown);
+        assertTrue(100 == recordsAdded);
+        assertTrue(info.getTxtRecord().length == 1300);
+    }
+
+    public void testParcel() throws Exception {
+        NsdServiceInfo emptyInfo = new NsdServiceInfo();
+        checkParcelable(emptyInfo);
+
+        NsdServiceInfo fullInfo = new NsdServiceInfo();
+        fullInfo.setServiceName("kitten");
+        fullInfo.setServiceType("_kitten._tcp");
+        fullInfo.setPort(4242);
+        fullInfo.setHost(LOCALHOST);
+        checkParcelable(fullInfo);
+
+        NsdServiceInfo noHostInfo = new NsdServiceInfo();
+        noHostInfo.setServiceName("kitten");
+        noHostInfo.setServiceType("_kitten._tcp");
+        noHostInfo.setPort(4242);
+        checkParcelable(noHostInfo);
+
+        NsdServiceInfo attributedInfo = new NsdServiceInfo();
+        attributedInfo.setServiceName("kitten");
+        attributedInfo.setServiceType("_kitten._tcp");
+        attributedInfo.setPort(4242);
+        attributedInfo.setHost(LOCALHOST);
+        attributedInfo.setAttribute("color", "pink");
+        attributedInfo.setAttribute("sound", (new String("にゃあ")).getBytes("UTF-8"));
+        attributedInfo.setAttribute("adorable", (String) null);
+        attributedInfo.setAttribute("sticky", "yes");
+        attributedInfo.setAttribute("siblings", new byte[] {});
+        attributedInfo.setAttribute("edge cases", new byte[] {0, -1, 127, -128});
+        attributedInfo.removeAttribute("sticky");
+        checkParcelable(attributedInfo);
+
+        // Sanity check that we actually wrote attributes to attributedInfo.
+        assertTrue(attributedInfo.getAttributes().keySet().contains("adorable"));
+        String sound = new String(attributedInfo.getAttributes().get("sound"), "UTF-8");
+        assertTrue(sound.equals("にゃあ"));
+        byte[] edgeCases = attributedInfo.getAttributes().get("edge cases");
+        assertTrue(Arrays.equals(edgeCases, new byte[] {0, -1, 127, -128}));
+        assertFalse(attributedInfo.getAttributes().keySet().contains("sticky"));
+    }
+
+    public void checkParcelable(NsdServiceInfo original) {
+        // Write to parcel.
+        Parcel p = Parcel.obtain();
+        Bundle writer = new Bundle();
+        writer.putParcelable("test_info", original);
+        writer.writeToParcel(p, 0);
+
+        // Extract from parcel.
+        p.setDataPosition(0);
+        Bundle reader = p.readBundle();
+        reader.setClassLoader(NsdServiceInfo.class.getClassLoader());
+        NsdServiceInfo result = reader.getParcelable("test_info");
+
+        // Assert equality of base fields.
+        assertEquality(original.getServiceName(), result.getServiceName());
+        assertEquality(original.getServiceType(), result.getServiceType());
+        assertEquality(original.getHost(), result.getHost());
+        assertTrue(original.getPort() == result.getPort());
+
+        // Assert equality of attribute map.
+        Map<String, byte[]> originalMap = original.getAttributes();
+        Map<String, byte[]> resultMap = result.getAttributes();
+        assertEquality(originalMap.keySet(), resultMap.keySet());
+        for (String key : originalMap.keySet()) {
+            assertTrue(Arrays.equals(originalMap.get(key), resultMap.get(key)));
+        }
+    }
+
+    public void assertEquality(Object expected, Object result) {
+        assertTrue(expected == result || expected.equals(result));
+    }
+
+    public void assertEmptyServiceInfo(NsdServiceInfo shouldBeEmpty) {
+        assertTrue(null == shouldBeEmpty.getTxtRecord());
+    }
+}
diff --git a/tests/DozeTest/Android.mk b/tests/DozeTest/Android.mk
new file mode 100644
index 0000000..01f10e5
--- /dev/null
+++ b/tests/DozeTest/Android.mk
@@ -0,0 +1,14 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+# Only compile source java files in this apk.
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := DozeTest
+
+include $(BUILD_PACKAGE)
+
+# Use the following include to make our test apk.
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/DozeTest/AndroidManifest.xml b/tests/DozeTest/AndroidManifest.xml
new file mode 100644
index 0000000..c199f69
--- /dev/null
+++ b/tests/DozeTest/AndroidManifest.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.dreams.dozetest">
+    <uses-permission android:name="android.permission.WAKE_LOCK" />
+
+    <application android:label="@string/app_name">
+        <service
+            android:name="DozeTestDream"
+            android:exported="true"
+            android:icon="@drawable/ic_app"
+            android:label="@string/doze_dream_name">
+            <!-- Commented out to prevent this dream from appearing in the list of
+                 dreams that the user can select via the Settings application.
+            <intent-filter>
+                <action android:name="android.service.dreams.DreamService" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+            -->
+        </service>
+    </application>
+</manifest>
diff --git a/tests/DozeTest/res/drawable-hdpi/ic_app.png b/tests/DozeTest/res/drawable-hdpi/ic_app.png
new file mode 100755
index 0000000..66a1984
--- /dev/null
+++ b/tests/DozeTest/res/drawable-hdpi/ic_app.png
Binary files differ
diff --git a/tests/DozeTest/res/drawable-mdpi/ic_app.png b/tests/DozeTest/res/drawable-mdpi/ic_app.png
new file mode 100644
index 0000000..5ae7701
--- /dev/null
+++ b/tests/DozeTest/res/drawable-mdpi/ic_app.png
Binary files differ
diff --git a/tests/DozeTest/res/layout/dream.xml b/tests/DozeTest/res/layout/dream.xml
new file mode 100644
index 0000000..1c8fd3f
--- /dev/null
+++ b/tests/DozeTest/res/layout/dream.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:gravity="center_vertical"
+        android:orientation="vertical">
+    <TextView
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/alarm_clock_label" />
+    <TextView android:id="@+id/alarm_clock"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content" />
+
+    <Space
+            android:layout_width="match_parent"
+            android:layout_height="32dp" />
+
+    <TextView
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/tick_clock_label" />
+    <TextClock android:id="@+id/tick_clock"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content" />
+</LinearLayout>
diff --git a/tests/DozeTest/res/values/strings.xml b/tests/DozeTest/res/values/strings.xml
new file mode 100644
index 0000000..f21911f
--- /dev/null
+++ b/tests/DozeTest/res/values/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<resources>
+    <!-- Name of the package of basic screensavers, shown in Settings > Apps. [CHAR LIMIT=40] -->
+    <string name="app_name">Doze Test</string>
+
+    <!-- Name of the screensaver. [CHAR LIMIT=40] -->
+    <string name="doze_dream_name">Doze Test</string>
+
+    <string name="alarm_clock_label">This clock is updated using the Alarm Manager</string>
+    <string name="tick_clock_label">This clock is updated using TIME_TICK Broadcasts</string>
+</resources>
diff --git a/tests/DozeTest/src/com/android/dreams/dozetest/DozeTestDream.java b/tests/DozeTest/src/com/android/dreams/dozetest/DozeTestDream.java
new file mode 100644
index 0000000..a0b2d1a
--- /dev/null
+++ b/tests/DozeTest/src/com/android/dreams/dozetest/DozeTestDream.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dreams.dozetest;
+
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.PowerManager;
+import android.service.dreams.DozeHardware;
+import android.service.dreams.DreamService;
+import android.text.format.DateFormat;
+import android.util.Log;
+import android.widget.TextView;
+
+import java.util.Date;
+
+/**
+ * Simple test for doze mode.
+ * <p>
+ * adb shell setprop debug.doze.component com.android.dreams.dozetest/.DozeTestDream
+ * </p>
+ */
+public class DozeTestDream extends DreamService {
+    private static final String TAG = DozeTestDream.class.getSimpleName();
+    private static final boolean DEBUG = false;
+
+    // Amount of time to allow to update the time shown on the screen before releasing
+    // the wakelock.  This timeout is design to compensate for the fact that we don't
+    // currently have a way to know when time display contents have actually been
+    // refreshed once the dream has finished rendering a new frame.
+    private static final int UPDATE_TIME_TIMEOUT = 100;
+
+    // A doze hardware message string we use for end-to-end testing.
+    // Doesn't mean anything.  Real hardware won't handle it.
+    private static final String TEST_PING_MESSAGE = "test.ping";
+
+    private PowerManager mPowerManager;
+    private PowerManager.WakeLock mWakeLock;
+    private AlarmManager mAlarmManager;
+    private PendingIntent mAlarmIntent;
+
+    private TextView mAlarmClock;
+
+    private final Date mTime = new Date();
+    private java.text.DateFormat mTimeFormat;
+
+    private boolean mDreaming;
+    private DozeHardware mDozeHardware;
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+
+        mPowerManager = (PowerManager)getSystemService(Context.POWER_SERVICE);
+        mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
+
+        mAlarmManager = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
+
+        Intent intent = new Intent("com.android.dreams.dozetest.ACTION_ALARM");
+        intent.setPackage(getPackageName());
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(intent.getAction());
+        registerReceiver(mAlarmReceiver, filter);
+        mAlarmIntent = PendingIntent.getBroadcast(this, 0, intent,
+                PendingIntent.FLAG_CANCEL_CURRENT);
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+
+        unregisterReceiver(mAlarmReceiver);
+        mAlarmIntent.cancel();
+    }
+
+    @Override
+    public void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        setInteractive(false);
+        setLowProfile(true);
+        setFullscreen(true);
+        setContentView(R.layout.dream);
+        setScreenBright(false);
+
+        mAlarmClock = (TextView)findViewById(R.id.alarm_clock);
+
+        mTimeFormat = DateFormat.getTimeFormat(this);
+    }
+
+    @Override
+    public void onDreamingStarted() {
+        super.onDreamingStarted();
+
+        mDreaming = true;
+        mDozeHardware = getDozeHardware();
+
+        Log.d(TAG, "Dream started: canDoze=" + canDoze()
+                + ", dozeHardware=" + mDozeHardware);
+
+        performTimeUpdate();
+
+        if (mDozeHardware != null) {
+            mDozeHardware.sendMessage(TEST_PING_MESSAGE, null);
+            mDozeHardware.setEnableMcu(true);
+        }
+        startDozing();
+    }
+
+    @Override
+    public void onDreamingStopped() {
+        super.onDreamingStopped();
+
+        mDreaming = false;
+        if (mDozeHardware != null) {
+            mDozeHardware.setEnableMcu(false);
+            mDozeHardware = null;
+        }
+
+        Log.d(TAG, "Dream ended: isDozing=" + isDozing());
+
+        stopDozing();
+        cancelTimeUpdate();
+    }
+
+    private void performTimeUpdate() {
+        if (mDreaming) {
+            long now = System.currentTimeMillis();
+            now -= now % 60000; // back up to last minute boundary
+
+            mTime.setTime(now);
+            mAlarmClock.setText(mTimeFormat.format(mTime));
+
+            mAlarmManager.setExact(AlarmManager.RTC_WAKEUP, now + 60000, mAlarmIntent);
+
+            mWakeLock.acquire(UPDATE_TIME_TIMEOUT);
+        }
+    }
+
+    private void cancelTimeUpdate() {
+        mAlarmManager.cancel(mAlarmIntent);
+    }
+
+    private final BroadcastReceiver mAlarmReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            performTimeUpdate();
+        }
+    };
+}
diff --git a/tools/aapt/AaptAssets.cpp b/tools/aapt/AaptAssets.cpp
index 19532e8..1f17316 100644
--- a/tools/aapt/AaptAssets.cpp
+++ b/tools/aapt/AaptAssets.cpp
@@ -1342,6 +1342,11 @@
               (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
               | ResTable_config::UI_MODE_TYPE_APPLIANCE;
         return true;
+    } else if (strcmp(name, "watch") == 0) {
+      if (out) out->uiMode =
+              (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
+              | ResTable_config::UI_MODE_TYPE_WATCH;
+        return true;
     }
 
     return false;
@@ -1856,9 +1861,18 @@
 // =========================================================================
 // =========================================================================
 
-status_t AaptGroup::addFile(const sp<AaptFile>& file)
+status_t AaptGroup::addFile(const sp<AaptFile>& file, const bool overwriteDuplicate)
 {
-    if (mFiles.indexOfKey(file->getGroupEntry()) < 0) {
+    ssize_t index = mFiles.indexOfKey(file->getGroupEntry());
+    if (index >= 0 && overwriteDuplicate) {
+        fprintf(stderr, "warning: overwriting '%s' with '%s'\n",
+                mFiles[index]->getSourceFile().string(),
+                file->getSourceFile().string());
+        removeFile(index);
+        index = -1;
+    }
+
+    if (index < 0) {
         file->mPath = mPath;
         mFiles.add(file->getGroupEntry(), file);
         return NO_ERROR;
@@ -1964,7 +1978,8 @@
     mDirs.removeItem(name);
 }
 
-status_t AaptDir::addLeafFile(const String8& leafName, const sp<AaptFile>& file)
+status_t AaptDir::addLeafFile(const String8& leafName, const sp<AaptFile>& file,
+        const bool overwrite)
 {
     sp<AaptGroup> group;
     if (mFiles.indexOfKey(leafName) >= 0) {
@@ -1974,12 +1989,12 @@
         mFiles.add(leafName, group);
     }
 
-    return group->addFile(file);
+    return group->addFile(file, overwrite);
 }
 
 ssize_t AaptDir::slurpFullTree(Bundle* bundle, const String8& srcDir,
                             const AaptGroupEntry& kind, const String8& resType,
-                            sp<FilePathStore>& fullResPaths)
+                            sp<FilePathStore>& fullResPaths, const bool overwrite)
 {
     Vector<String8> fileNames;
     {
@@ -2038,7 +2053,7 @@
                 notAdded = true;
             }
             ssize_t res = subdir->slurpFullTree(bundle, pathName, kind,
-                                                resType, fullResPaths);
+                                                resType, fullResPaths, overwrite);
             if (res < NO_ERROR) {
                 return res;
             }
@@ -2048,7 +2063,7 @@
             count += res;
         } else if (type == kFileTypeRegular) {
             sp<AaptFile> file = new AaptFile(pathName, kind, resType);
-            status_t err = addLeafFile(fileNames[i], file);
+            status_t err = addLeafFile(fileNames[i], file, overwrite);
             if (err != NO_ERROR) {
                 return err;
             }
@@ -2316,24 +2331,24 @@
     /*
      * If a directory of custom assets was supplied, slurp 'em up.
      */
-    if (bundle->getAssetSourceDir()) {
-        const char* assetDir = bundle->getAssetSourceDir();
-
-        FileType type = getFileType(assetDir);
+    const Vector<const char*>& assetDirs = bundle->getAssetSourceDirs();
+    const int AN = assetDirs.size();
+    for (int i = 0; i < AN; i++) {
+        FileType type = getFileType(assetDirs[i]);
         if (type == kFileTypeNonexistent) {
-            fprintf(stderr, "ERROR: asset directory '%s' does not exist\n", assetDir);
+            fprintf(stderr, "ERROR: asset directory '%s' does not exist\n", assetDirs[i]);
             return UNKNOWN_ERROR;
         }
         if (type != kFileTypeDirectory) {
-            fprintf(stderr, "ERROR: '%s' is not a directory\n", assetDir);
+            fprintf(stderr, "ERROR: '%s' is not a directory\n", assetDirs[i]);
             return UNKNOWN_ERROR;
         }
 
-        String8 assetRoot(assetDir);
+        String8 assetRoot(assetDirs[i]);
         sp<AaptDir> assetAaptDir = makeDir(String8(kAssetDir));
         AaptGroupEntry group;
         count = assetAaptDir->slurpFullTree(bundle, assetRoot, group,
-                                            String8(), mFullAssetPaths);
+                                            String8(), mFullAssetPaths, true);
         if (count < 0) {
             totalCount = count;
             goto bail;
@@ -2343,9 +2358,10 @@
         }
         totalCount += count;
 
-        if (bundle->getVerbose())
+        if (bundle->getVerbose()) {
             printf("Found %d custom asset file%s in %s\n",
-                   count, (count==1) ? "" : "s", assetDir);
+                   count, (count==1) ? "" : "s", assetDirs[i]);
+        }
     }
 
     /*
diff --git a/tools/aapt/AaptAssets.h b/tools/aapt/AaptAssets.h
index 9733b6d..336d08b 100644
--- a/tools/aapt/AaptAssets.h
+++ b/tools/aapt/AaptAssets.h
@@ -299,7 +299,7 @@
     const DefaultKeyedVector<AaptGroupEntry, sp<AaptFile> >& getFiles() const
         { return mFiles; }
 
-    status_t addFile(const sp<AaptFile>& file);
+    status_t addFile(const sp<AaptFile>& file, const bool overwriteDuplicate=false);
     void removeFile(size_t index);
 
     void print(const String8& prefix) const;
@@ -365,12 +365,14 @@
     status_t addDir(const String8& name, const sp<AaptDir>& dir);
     sp<AaptDir> makeDir(const String8& name);
     status_t addLeafFile(const String8& leafName,
-                         const sp<AaptFile>& file);
+                         const sp<AaptFile>& file,
+                         const bool overwrite=false);
     virtual ssize_t slurpFullTree(Bundle* bundle,
                                   const String8& srcDir,
                                   const AaptGroupEntry& kind,
                                   const String8& resType,
-                                  sp<FilePathStore>& fullResPaths);
+                                  sp<FilePathStore>& fullResPaths,
+                                  const bool overwrite=false);
 
     String8 mLeaf;
     String8 mPath;
diff --git a/tools/aapt/Android.mk b/tools/aapt/Android.mk
index 2949f8e..806f8ff 100644
--- a/tools/aapt/Android.mk
+++ b/tools/aapt/Android.mk
@@ -5,7 +5,7 @@
 #
 
 # This tool is prebuilt if we're doing an app-only build.
-ifeq ($(TARGET_BUILD_APPS),)
+ifeq ($(TARGET_BUILD_APPS)$(filter true,$(TARGET_BUILD_PDK)),)
 
 
 aapt_src_files := \
@@ -101,4 +101,4 @@
 include $(BUILD_EXECUTABLE)
 endif
 
-endif # TARGET_BUILD_APPS
+endif # No TARGET_BUILD_APPS or TARGET_BUILD_PDK
diff --git a/tools/aapt/Bundle.h b/tools/aapt/Bundle.h
index a6f2442..382cf5e 100644
--- a/tools/aapt/Bundle.h
+++ b/tools/aapt/Bundle.h
@@ -64,7 +64,6 @@
           mCompressionMethod(0), mJunkPath(false), mOutputAPKFile(NULL),
           mManifestPackageNameOverride(NULL), mInstrumentationPackageNameOverride(NULL),
           mAutoAddOverlay(false), mGenDependencies(false),
-          mAssetSourceDir(NULL),
           mCrunchedOutputDir(NULL), mProguardFile(NULL),
           mAndroidManifestFile(NULL), mPublicOutputFile(NULL),
           mRClassDir(NULL), mResourceIntermediatesDir(NULL), mManifestMinSdkVersion(NULL),
@@ -132,8 +131,8 @@
     /*
      * Input options.
      */
-    const char* getAssetSourceDir() const { return mAssetSourceDir; }
-    void setAssetSourceDir(const char* dir) { mAssetSourceDir = dir; }
+    const android::Vector<const char*>& getAssetSourceDirs() const { return mAssetSourceDirs; }
+    void addAssetSourceDir(const char* dir) { mAssetSourceDirs.insertAt(dir,0); }
     const char* getCrunchedOutputDir() const { return mCrunchedOutputDir; }
     void setCrunchedOutputDir(const char* dir) { mCrunchedOutputDir = dir; }
     const char* getProguardFile() const { return mProguardFile; }
@@ -281,6 +280,7 @@
     android::Vector<const char*> mPackageIncludes;
     android::Vector<const char*> mJarFiles;
     android::Vector<const char*> mNoCompressExtensions;
+    android::Vector<const char*> mAssetSourceDirs;
     android::Vector<const char*> mResourceSourceDirs;
 
     const char* mManifestMinSdkVersion;
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index f7de558..34292fe 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -375,6 +375,7 @@
     LARGEST_WIDTH_LIMIT_DP_ATTR = 0x01010366,
     PUBLIC_KEY_ATTR = 0x010103a6,
     CATEGORY_ATTR = 0x010103e8,
+    BANNER_ATTR = 0x10103f2,
 };
 
 const char *getComponentName(String8 &pkgName, String8 &componentName) {
@@ -678,6 +679,7 @@
             bool withinActivity = false;
             bool isMainActivity = false;
             bool isLauncherActivity = false;
+            bool isLeanbackLauncherActivity = false;
             bool isSearchable = false;
             bool withinApplication = false;
             bool withinSupportsInput = false;
@@ -788,6 +790,7 @@
             String8 activityName;
             String8 activityLabel;
             String8 activityIcon;
+            String8 activityBanner;
             String8 receiverName;
             String8 serviceName;
             Vector<String8> supportedInput;
@@ -811,15 +814,27 @@
                         withinApplication = false;
                         withinSupportsInput = false;
                     } else if (depth < 3) {
-                        if (withinActivity && isMainActivity && isLauncherActivity) {
+                        if (withinActivity && isMainActivity) {
                             const char *aName = getComponentName(pkg, activityName);
-                            printf("launchable-activity:");
-                            if (aName != NULL) {
-                                printf(" name='%s' ", aName);
+                            if (isLauncherActivity) {
+                                printf("launchable-activity:");
+                                if (aName != NULL) {
+                                    printf(" name='%s' ", aName);
+                                }
+                                printf(" label='%s' icon='%s'\n",
+                                        activityLabel.string(),
+                                        activityIcon.string());
                             }
-                            printf(" label='%s' icon='%s'\n",
-                                    activityLabel.string(),
-                                    activityIcon.string());
+                            if (isLeanbackLauncherActivity) {
+                                printf("leanback-launchable-activity:");
+                                if (aName != NULL) {
+                                    printf(" name='%s' ", aName);
+                                }
+                                printf(" label='%s' icon='%s' banner='%s'\n",
+                                        activityLabel.string(),
+                                        activityIcon.string(),
+                                        activityBanner.string());
+                            }
                         }
                         if (!hasIntentFilter) {
                             hasOtherActivities |= withinActivity;
@@ -837,7 +852,7 @@
                         withinService = false;
                         withinReceiver = false;
                         hasIntentFilter = false;
-                        isMainActivity = isLauncherActivity = false;
+                        isMainActivity = isLauncherActivity = isLeanbackLauncherActivity = false;
                     } else if (depth < 4) {
                         if (withinIntentFilter) {
                             if (withinActivity) {
@@ -1232,6 +1247,13 @@
                                 goto bail;
                             }
 
+                            activityBanner = getResolvedAttribute(&res, tree, BANNER_ATTR, &error);
+                            if (error != "") {
+                                fprintf(stderr, "ERROR getting 'android:banner' attribute: %s\n",
+                                        error.string());
+                                goto bail;
+                            }
+
                             int32_t orien = getResolvedIntegerAttribute(&res, tree,
                                     SCREEN_ORIENTATION_ATTR, &error);
                             if (error == "") {
@@ -1413,6 +1435,8 @@
                         if (withinActivity) {
                             if (category == "android.intent.category.LAUNCHER") {
                                 isLauncherActivity = true;
+                            } else if (category == "android.intent.category.LEANBACK_LAUNCHER") {
+                                isLeanbackLauncherActivity = true;
                             }
                         }
                     }
@@ -1900,7 +1924,7 @@
 
     N = bundle->getFileSpecCount();
     if (N < 1 && bundle->getResourceSourceDirs().size() == 0 && bundle->getJarFiles().size() == 0
-            && bundle->getAndroidManifestFile() == NULL && bundle->getAssetSourceDir() == NULL) {
+            && bundle->getAndroidManifestFile() == NULL && bundle->getAssetSourceDirs().size() == 0) {
         fprintf(stderr, "ERROR: no input files\n");
         goto bail;
     }
diff --git a/tools/aapt/Main.cpp b/tools/aapt/Main.cpp
index 977226b..d1d3deb 100644
--- a/tools/aapt/Main.cpp
+++ b/tools/aapt/Main.cpp
@@ -345,7 +345,7 @@
                     goto bail;
                 }
                 convertPath(argv[0]);
-                bundle.setAssetSourceDir(argv[0]);
+                bundle.addAssetSourceDir(argv[0]);
                 break;
             case 'G':
                 argc--;
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index 4d29ff7..42b1905 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -1237,12 +1237,13 @@
         while ((err=it.next()) == NO_ERROR) {
             String8 src = it.getFile()->getPrintableSource();
             err = compileXmlFile(assets, it.getFile(), &table, xmlFlags);
-            if (err != NO_ERROR) {
+            if (err == NO_ERROR) {
+                ResXMLTree block;
+                block.setTo(it.getFile()->getData(), it.getFile()->getSize(), true);
+                checkForIds(src, block);
+            } else {
                 hasErrors = true;
             }
-            ResXMLTree block;
-            block.setTo(it.getFile()->getData(), it.getFile()->getSize(), true);
-            checkForIds(src, block);
         }
 
         if (err < NO_ERROR) {
diff --git a/tools/aidl/Android.mk b/tools/aidl/Android.mk
index 77d46ab..efd60a2 100644
--- a/tools/aidl/Android.mk
+++ b/tools/aidl/Android.mk
@@ -3,7 +3,7 @@
 # Copies files into the directory structure described by a manifest
 
 # This tool is prebuilt if we're doing an app-only build.
-ifeq ($(TARGET_BUILD_APPS),)
+ifeq ($(TARGET_BUILD_APPS)$(filter true,$(TARGET_BUILD_PDK)),)
 
 LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
@@ -26,4 +26,4 @@
 
 include $(BUILD_HOST_EXECUTABLE)
 
-endif # TARGET_BUILD_APPS
+endif # No TARGET_BUILD_APPS or TARGET_BUILD_PDK
diff --git a/tools/layoutlib/Android.mk b/tools/layoutlib/Android.mk
index 1fa9615..cb68340 100644
--- a/tools/layoutlib/Android.mk
+++ b/tools/layoutlib/Android.mk
@@ -53,6 +53,7 @@
 $(LOCAL_BUILT_MODULE): $(built_core_dep) \
                        $(built_framework_dep) \
                        $(built_ext_dep) \
+                       $(built_ext_data) \
                        $(built_layoutlib_create_jar)
 	$(hide) echo "host layoutlib_create: $@"
 	$(hide) mkdir -p $(dir $@)
diff --git a/tools/layoutlib/bridge/resources/bars/action_bar.xml b/tools/layoutlib/bridge/resources/bars/action_bar.xml
deleted file mode 100644
index 7adc5af..0000000
--- a/tools/layoutlib/bridge/resources/bars/action_bar.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<merge xmlns:android="http://schemas.android.com/apk/res/android">
-    <include layout="@android:layout/action_bar_home" />
-    <TextView
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"/>
-</merge>
diff --git a/tools/layoutlib/bridge/src/android/content/res/AssetManager_Delegate.java b/tools/layoutlib/bridge/src/android/content/res/AssetManager_Delegate.java
new file mode 100644
index 0000000..5c2b793
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/content/res/AssetManager_Delegate.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.res;
+
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+/**
+ * Delegate used to provide implementation of a select few native methods of {@link AssetManager}
+ * <p/>
+ * Through the layoutlib_create tool, the original native methods of AssetManager have been replaced
+ * by calls to methods of the same name in this delegate class.
+ *
+ */
+public class AssetManager_Delegate {
+
+    @LayoutlibDelegate
+    /*package*/ static long newTheme(AssetManager manager) {
+        return Resources_Theme_Delegate.getDelegateManager()
+                .addNewDelegate(new Resources_Theme_Delegate());
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static void deleteTheme(AssetManager manager, long theme) {
+        Resources_Theme_Delegate.getDelegateManager().removeJavaReferenceFor(theme);
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static void applyThemeStyle(long theme, int styleRes, boolean force) {
+        Resources_Theme_Delegate delegate = Resources_Theme_Delegate.getDelegateManager()
+                .getDelegate(theme);
+        delegate.mThemeResId = styleRes;
+        delegate.force = force;
+    }
+}
diff --git a/tools/layoutlib/bridge/src/android/content/res/Resources_Theme_Delegate.java b/tools/layoutlib/bridge/src/android/content/res/Resources_Theme_Delegate.java
index c9d615c..b89d15f 100644
--- a/tools/layoutlib/bridge/src/android/content/res/Resources_Theme_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/content/res/Resources_Theme_Delegate.java
@@ -16,7 +16,13 @@
 
 package android.content.res;
 
+import com.android.annotations.Nullable;
+import com.android.ide.common.rendering.api.ResourceReference;
+import com.android.ide.common.rendering.api.StyleResourceValue;
+import com.android.layoutlib.bridge.android.BridgeContext;
+import com.android.layoutlib.bridge.impl.DelegateManager;
 import com.android.layoutlib.bridge.impl.RenderSessionImpl;
+import com.android.resources.ResourceType;
 import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
 
 import android.content.res.Resources.NotFoundException;
@@ -25,7 +31,7 @@
 import android.util.TypedValue;
 
 /**
- * Delegate used to provide new implementation of a select few methods of {@link Resources$Theme}
+ * Delegate used to provide new implementation of a select few methods of {@link Resources.Theme}
  *
  * Through the layoutlib_create tool, the original  methods of Theme have been replaced
  * by calls to methods of the same name in this delegate class.
@@ -33,11 +39,30 @@
  */
 public class Resources_Theme_Delegate {
 
+    // Resource identifier for the theme.
+    int mThemeResId;
+    // Whether to use the Theme.mThemeResId as primary theme.
+    boolean force;
+
+    // ---- delegate manager ----
+
+    private static final DelegateManager<Resources_Theme_Delegate> sManager =
+            new DelegateManager<Resources_Theme_Delegate>(Resources_Theme_Delegate.class);
+
+    public static DelegateManager<Resources_Theme_Delegate> getDelegateManager() {
+        return sManager;
+    }
+
+    // ---- delegate methods. ----
+
     @LayoutlibDelegate
     /*package*/ static TypedArray obtainStyledAttributes(
             Resources thisResources, Theme thisTheme,
             int[] attrs) {
-        return RenderSessionImpl.getCurrentContext().obtainStyledAttributes(attrs);
+        boolean changed = setupResources(thisTheme);
+        TypedArray ta = RenderSessionImpl.getCurrentContext().obtainStyledAttributes(attrs);
+        restoreResources(changed);
+        return ta;
     }
 
     @LayoutlibDelegate
@@ -45,15 +70,21 @@
             Resources thisResources, Theme thisTheme,
             int resid, int[] attrs)
             throws NotFoundException {
-        return RenderSessionImpl.getCurrentContext().obtainStyledAttributes(resid, attrs);
+        boolean changed = setupResources(thisTheme);
+        TypedArray ta = RenderSessionImpl.getCurrentContext().obtainStyledAttributes(resid, attrs);
+        restoreResources(changed);
+        return ta;
     }
 
     @LayoutlibDelegate
     /*package*/ static TypedArray obtainStyledAttributes(
             Resources thisResources, Theme thisTheme,
             AttributeSet set, int[] attrs, int defStyleAttr, int defStyleRes) {
-        return RenderSessionImpl.getCurrentContext().obtainStyledAttributes(
-                set, attrs, defStyleAttr, defStyleRes);
+        boolean changed = setupResources(thisTheme);
+        TypedArray ta = RenderSessionImpl.getCurrentContext().obtainStyledAttributes(set, attrs,
+                defStyleAttr, defStyleRes);
+        restoreResources(changed);
+        return ta;
     }
 
     @LayoutlibDelegate
@@ -61,7 +92,45 @@
             Resources thisResources, Theme thisTheme,
             int resid, TypedValue outValue,
             boolean resolveRefs) {
-        return RenderSessionImpl.getCurrentContext().resolveThemeAttribute(
+        boolean changed = setupResources(thisTheme);
+        boolean found =  RenderSessionImpl.getCurrentContext().resolveThemeAttribute(
                 resid, outValue, resolveRefs);
+        restoreResources(changed);
+        return found;
+    }
+
+    // ---- private helper methods ----
+
+    private static boolean setupResources(Theme thisTheme) {
+        Resources_Theme_Delegate themeDelegate = sManager.getDelegate(thisTheme.getNativeTheme());
+        StyleResourceValue style = resolveStyle(themeDelegate.mThemeResId);
+        if (style != null) {
+            RenderSessionImpl.getCurrentContext().getRenderResources()
+                    .applyStyle(style, themeDelegate.force);
+            return true;
+        }
+        return false;
+    }
+
+    private static void restoreResources(boolean changed) {
+        if (changed) {
+            RenderSessionImpl.getCurrentContext().getRenderResources().clearStyles();
+        }
+    }
+
+    @Nullable
+    private static StyleResourceValue resolveStyle(int nativeResid) {
+        if (nativeResid == 0) {
+            return null;
+        }
+        BridgeContext context = RenderSessionImpl.getCurrentContext();
+        ResourceReference theme = context.resolveId(nativeResid);
+        if (theme.isFramework()) {
+            return (StyleResourceValue) context.getRenderResources()
+                    .getFrameworkResource(ResourceType.STYLE, theme.getName());
+        } else {
+            return (StyleResourceValue) context.getRenderResources()
+                    .getProjectResource(ResourceType.STYLE, theme.getName());
+        }
     }
 }
diff --git a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
index 89d7e23..7016136 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
@@ -518,7 +518,8 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void nativeSetHasAlpha(long nativeBitmap, boolean hasAlpha) {
+    /*package*/ static void nativeSetAlphaAndPremultiplied(long nativeBitmap, boolean hasAlpha,
+            boolean isPremul) {
         // get the delegate from the native int.
         Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
         if (delegate == null) {
diff --git a/tools/layoutlib/bridge/src/android/graphics/Region_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Region_Delegate.java
index ea23649..d2aae92 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Region_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Region_Delegate.java
@@ -275,21 +275,21 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static boolean nativeSetRegion(long native_dst, long native_src) {
+    /*package*/ static void nativeSetRegion(long native_dst, long native_src) {
         Region_Delegate dstRegion = sManager.getDelegate(native_dst);
         if (dstRegion == null) {
-            return true;
+            return;
         }
 
         Region_Delegate srcRegion = sManager.getDelegate(native_src);
         if (srcRegion == null) {
-            return true;
+            return;
         }
 
         dstRegion.mArea.reset();
         dstRegion.mArea.add(srcRegion.mArea);
 
-        return true;
+        return;
     }
 
     @LayoutlibDelegate
diff --git a/tools/layoutlib/bridge/src/android/view/BridgeInflater.java b/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
index 941f1ce6..a2e93a7 100644
--- a/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
+++ b/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
@@ -32,10 +32,6 @@
 
 import android.content.Context;
 import android.util.AttributeSet;
-import android.view.InflateException;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
 
 import java.io.File;
 
@@ -154,6 +150,9 @@
     @Override
     public View inflate(int resource, ViewGroup root) {
         Context context = getContext();
+        if (context instanceof ContextThemeWrapper) {
+            context = ((ContextThemeWrapper) context).getBaseContext();
+        }
         if (context instanceof BridgeContext) {
             BridgeContext bridgeContext = (BridgeContext)context;
 
@@ -216,43 +215,16 @@
     }
 
     private void setupViewInContext(View view, AttributeSet attrs) {
-        if (getContext() instanceof BridgeContext) {
-            BridgeContext bc = (BridgeContext) getContext();
-            if (attrs instanceof BridgeXmlBlockParser) {
-                BridgeXmlBlockParser parser = (BridgeXmlBlockParser) attrs;
-
-                // get the view key
-                Object viewKey = parser.getViewCookie();
-
-                if (viewKey == null) {
-                    int currentDepth = parser.getDepth();
-
-                    // test whether we are in an included file or in a adapter binding view.
-                    BridgeXmlBlockParser previousParser = bc.getPreviousParser();
-                    if (previousParser != null) {
-                        // looks like we inside an embedded layout.
-                        // only apply the cookie of the calling node (<include>) if we are at the
-                        // top level of the embedded layout. If there is a merge tag, then
-                        // skip it and look for the 2nd level
-                        int testDepth = mIsInMerge ? 2 : 1;
-                        if (currentDepth == testDepth) {
-                            viewKey = previousParser.getViewCookie();
-                            // if we are in a merge, wrap the cookie in a MergeCookie.
-                            if (viewKey != null && mIsInMerge) {
-                                viewKey = new MergeCookie(viewKey);
-                            }
-                        }
-                    } else if (mResourceReference != null && currentDepth == 1) {
-                        // else if there's a resource reference, this means we are in an adapter
-                        // binding case. Set the resource ref as the view cookie only for the top
-                        // level view.
-                        viewKey = mResourceReference;
-                    }
-                }
-
-                if (viewKey != null) {
-                    bc.addViewKey(view, viewKey);
-                }
+        Context context = getContext();
+        if (context instanceof ContextThemeWrapper) {
+            context = ((ContextThemeWrapper) context).getBaseContext();
+        }
+        if (context instanceof BridgeContext) {
+            BridgeContext bc = (BridgeContext) context;
+            // get the view key
+            Object viewKey = getViewKeyFromParser(attrs, bc, mResourceReference, mIsInMerge);
+            if (viewKey != null) {
+                bc.addViewKey(view, viewKey);
             }
         }
     }
@@ -269,4 +241,44 @@
     public LayoutInflater cloneInContext(Context newContext) {
         return new BridgeInflater(this, newContext);
     }
+
+    /*package*/ static Object getViewKeyFromParser(AttributeSet attrs, BridgeContext bc,
+            ResourceReference resourceReference, boolean isInMerge) {
+
+        if (!(attrs instanceof BridgeXmlBlockParser)) {
+            return null;
+        }
+        BridgeXmlBlockParser parser = ((BridgeXmlBlockParser) attrs);
+
+        // get the view key
+        Object viewKey = parser.getViewCookie();
+
+        if (viewKey == null) {
+            int currentDepth = parser.getDepth();
+
+            // test whether we are in an included file or in a adapter binding view.
+            BridgeXmlBlockParser previousParser = bc.getPreviousParser();
+            if (previousParser != null) {
+                // looks like we are inside an embedded layout.
+                // only apply the cookie of the calling node (<include>) if we are at the
+                // top level of the embedded layout. If there is a merge tag, then
+                // skip it and look for the 2nd level
+                int testDepth = isInMerge ? 2 : 1;
+                if (currentDepth == testDepth) {
+                    viewKey = previousParser.getViewCookie();
+                    // if we are in a merge, wrap the cookie in a MergeCookie.
+                    if (viewKey != null && isInMerge) {
+                        viewKey = new MergeCookie(viewKey);
+                    }
+                }
+            } else if (resourceReference != null && currentDepth == 1) {
+                // else if there's a resource reference, this means we are in an adapter
+                // binding case. Set the resource ref as the view cookie only for the top
+                // level view.
+                viewKey = resourceReference;
+            }
+        }
+
+        return viewKey;
+    }
 }
diff --git a/tools/layoutlib/bridge/src/android/view/MenuInflater_Delegate.java b/tools/layoutlib/bridge/src/android/view/MenuInflater_Delegate.java
new file mode 100644
index 0000000..e34ad38b
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/view/MenuInflater_Delegate.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import android.content.Context;
+import com.android.ide.common.rendering.api.LayoutLog;
+import com.android.ide.common.rendering.api.ViewInfo;
+import com.android.internal.view.menu.BridgeMenuItemImpl;
+import com.android.internal.view.menu.MenuView;
+import com.android.layoutlib.bridge.Bridge;
+import com.android.layoutlib.bridge.android.BridgeContext;
+import com.android.layoutlib.bridge.android.BridgeXmlBlockParser;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import android.util.AttributeSet;
+
+/**
+ * Delegate used to provide new implementation of a select few methods of {@link MenuInflater}
+ * <p/>
+ * Through the layoutlib_create tool, the original  methods of MenuInflater have been
+ * replaced by calls to methods of the same name in this delegate class.
+ * <p/>
+ * The main purpose of the class is to get the view key from the menu xml parser and add it to
+ * the menu item. The view key is used by the IDE to match the individual view elements to the
+ * corresponding xml tag in the menu/layout file.
+ * <p/>
+ * For Menus, the views may be reused and the {@link MenuItem} is a better object to hold the
+ * view key than the {@link MenuView.ItemView}. At the time of computation of the rest of {@link
+ * ViewInfo}, we check the corresponding view key in the menu item for the view and add it
+ */
+public class MenuInflater_Delegate {
+
+    @LayoutlibDelegate
+    /*package*/ static void registerMenu(MenuInflater thisInflater, MenuItem menuItem,
+            AttributeSet attrs) {
+        if (menuItem instanceof BridgeMenuItemImpl) {
+            Context context = thisInflater.getContext();
+            if (context instanceof ContextThemeWrapper) {
+                context = ((ContextThemeWrapper) context).getBaseContext();
+            }
+            if (context instanceof BridgeContext) {
+                Object viewKey = BridgeInflater.getViewKeyFromParser(
+                        attrs, ((BridgeContext) context), null, false);
+                ((BridgeMenuItemImpl) menuItem).setViewCookie(viewKey);
+                return;
+            }
+        }
+        // This means that Bridge did not take over the instantiation of some object properly.
+        // This is most likely a bug in the LayoutLib code.
+        Bridge.getLog().warning(LayoutLog.TAG_BROKEN,
+                "Action Bar Menu rendering may be incorrect.", null);
+
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static void registerMenu(MenuInflater thisInflater, SubMenu subMenu,
+            AttributeSet parser) {
+        registerMenu(thisInflater, subMenu.getItem(), parser);
+    }
+
+}
diff --git a/tools/layoutlib/bridge/src/com/android/internal/view/menu/BridgeMenuItemImpl.java b/tools/layoutlib/bridge/src/com/android/internal/view/menu/BridgeMenuItemImpl.java
new file mode 100644
index 0000000..cdb839a
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/internal/view/menu/BridgeMenuItemImpl.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.view.menu;
+
+import com.android.layoutlib.bridge.android.BridgeContext;
+
+import android.content.Context;
+import android.view.ContextThemeWrapper;
+import android.view.View;
+
+/**
+ * An extension of the {@link MenuItemImpl} to store the view cookie also.
+ */
+public class BridgeMenuItemImpl extends MenuItemImpl {
+
+    /**
+     * An object returned by the IDE that helps mapping each View to the corresponding XML tag in
+     * the layout. For Menus, we store this cookie here and attach it to the corresponding view
+     * at the time of rendering.
+     */
+    private Object viewCookie;
+    private BridgeContext mContext;
+
+    /**
+     * Instantiates this menu item.
+     */
+    BridgeMenuItemImpl(MenuBuilder menu, int group, int id, int categoryOrder, int ordering,
+            CharSequence title, int showAsAction) {
+        super(menu, group, id, categoryOrder, ordering, title, showAsAction);
+        Context context = menu.getContext();
+        if (context instanceof ContextThemeWrapper) {
+            context = ((ContextThemeWrapper) context).getBaseContext();
+        }
+        if (context instanceof BridgeContext) {
+            mContext = ((BridgeContext) context);
+        }
+    }
+
+    public Object getViewCookie() {
+        return viewCookie;
+    }
+
+    public void setViewCookie(Object viewCookie) {
+        // If the menu item has an associated action provider view,
+        // directly set the cookie in the view to cookie map stored in BridgeContext.
+        View actionView = getActionView();
+        if (actionView != null && mContext != null) {
+            mContext.addViewKey(actionView, viewCookie);
+            // We don't need to add the view cookie to the this item now. But there's no harm in
+            // storing it, in case we need it in the future.
+        }
+        this.viewCookie = viewCookie;
+    }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/internal/view/menu/MenuBuilderAccessor.java b/tools/layoutlib/bridge/src/com/android/internal/view/menu/MenuBuilderAccessor.java
new file mode 100644
index 0000000..f0798cb
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/internal/view/menu/MenuBuilderAccessor.java
@@ -0,0 +1,12 @@
+package com.android.internal.view.menu;
+
+import java.util.ArrayList;
+
+/**
+ * To access non public members of {@link MenuBuilder}
+ */
+public class MenuBuilderAccessor {
+    public static ArrayList<MenuItemImpl> getNonActionItems(MenuBuilder builder) {
+        return builder.getNonActionItems();
+    }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/internal/view/menu/MenuBuilder_Delegate.java b/tools/layoutlib/bridge/src/com/android/internal/view/menu/MenuBuilder_Delegate.java
new file mode 100644
index 0000000..505fb81
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/internal/view/menu/MenuBuilder_Delegate.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.view.menu;
+
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+/**
+ * Delegate used to provide new implementation of a select few methods of {@link MenuBuilder}
+ * <p/>
+ * Through the layoutlib_create tool, the original  methods of {@code MenuBuilder} have been
+ * replaced by calls to methods of the same name in this delegate class.
+ */
+public class MenuBuilder_Delegate {
+    /**
+     * The method overrides the instantiation of the {@link MenuItemImpl} with an instance of
+     * {@link BridgeMenuItemImpl} so that view cookies may be stored.
+     */
+    @LayoutlibDelegate
+    /*package*/ static MenuItemImpl createNewMenuItem(MenuBuilder thisMenu, int group, int id,
+            int categoryOrder, int ordering, CharSequence title, int defaultShowAsAction) {
+        return new BridgeMenuItemImpl(thisMenu, group, id, categoryOrder, ordering, title,
+                defaultShowAsAction);
+    }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/internal/widget/ActionBarAccessor.java b/tools/layoutlib/bridge/src/com/android/internal/widget/ActionBarAccessor.java
new file mode 100644
index 0000000..47a3679
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/internal/widget/ActionBarAccessor.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.widget;
+
+import com.android.internal.view.menu.ActionMenuPresenter;
+
+/**
+ * To access non public members of AbsActionBarView
+ */
+public class ActionBarAccessor {
+
+    /**
+     * Returns the {@link ActionMenuPresenter} associated with the {@link AbsActionBarView}
+     */
+    public static ActionMenuPresenter getActionMenuPresenter(AbsActionBarView view) {
+        return view.mActionMenuPresenter;
+    }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
index ab4be71..fa8050f 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
@@ -215,7 +215,8 @@
                 Capability.ADAPTER_BINDING,
                 Capability.EXTENDED_VIEWINFO,
                 Capability.FIXED_SCALABLE_NINE_PATCH,
-                Capability.RTL);
+                Capability.RTL,
+                Capability.ACTION_BAR);
 
 
         BridgeAssetManager.initSystem();
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java
index f9f4b3a..e0f87fd 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java
@@ -64,6 +64,11 @@
     }
 
     @Override
+    public List<ViewInfo> getSystemRootViews() {
+        return mSession.getSystemViewInfos();
+    }
+
+    @Override
     public Map<String, String> getDefaultProperties(Object viewObject) {
         return mSession.getDefaultProperties(viewObject);
     }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index b9294ab..6595ce1 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -16,6 +16,7 @@
 
 package com.android.layoutlib.bridge.android;
 
+import com.android.annotations.Nullable;
 import com.android.ide.common.rendering.api.ILayoutPullParser;
 import com.android.ide.common.rendering.api.IProjectCallback;
 import com.android.ide.common.rendering.api.LayoutLog;
@@ -109,7 +110,7 @@
     // maps for dynamically generated id representing style objects (StyleResourceValue)
     private Map<Integer, StyleResourceValue> mDynamicIdToStyleMap;
     private Map<StyleResourceValue, Integer> mStyleToDynamicIdMap;
-    private int mDynamicIdGenerator = 0x01030000; // Base id for framework R.style
+    private int mDynamicIdGenerator = 0x02030000; // Base id for R.style in custom namespace
 
     // cache for TypedArray generated from IStyleResourceValue object
     private Map<int[], Map<Integer, TypedArray>> mTypedArrayCache;
@@ -315,6 +316,11 @@
             }
         }
 
+        // The base value for R.style is 0x01030000 and the custom style is 0x02030000.
+        // So, if the second byte is 03, it's probably a style.
+        if ((id >> 16 & 0xFF) == 0x03) {
+            return getStyleByDynamicId(id);
+        }
         return null;
     }
 
@@ -455,7 +461,10 @@
 
     @Override
     public final TypedArray obtainStyledAttributes(int[] attrs) {
-        return createStyleBasedTypedArray(mRenderResources.getCurrentTheme(), attrs);
+        // No style is specified here, so create the typed array based on the default theme
+        // and the styles already applied to it. A null value of style indicates that the default
+        // theme should be used.
+        return createStyleBasedTypedArray(null, attrs);
     }
 
     @Override
@@ -604,7 +613,8 @@
             }
 
             if (value != null) {
-                if (value.getFirst() == ResourceType.STYLE) {
+                if ((value.getFirst() == ResourceType.STYLE)
+                        || (value.getFirst() == ResourceType.ATTR)) {
                     // look for the style in the current theme, and its parent:
                     ResourceValue item = mRenderResources.findItemInTheme(value.getSecond(),
                             isFrameworkRes);
@@ -723,11 +733,13 @@
 
     /**
      * Creates a {@link BridgeTypedArray} by filling the values defined by the int[] with the
-     * values found in the given style.
+     * values found in the given style. If no style is specified, the default theme, along with the
+     * styles applied to it are used.
+     *
      * @see #obtainStyledAttributes(int, int[])
      */
-    private BridgeTypedArray createStyleBasedTypedArray(StyleResourceValue style, int[] attrs)
-            throws Resources.NotFoundException {
+    private BridgeTypedArray createStyleBasedTypedArray(@Nullable StyleResourceValue style,
+            int[] attrs) throws Resources.NotFoundException {
 
         List<Pair<String, Boolean>> attributes = searchAttrs(attrs);
 
@@ -740,8 +752,14 @@
 
             if (attribute != null) {
                 // look for the value in the given style
-                ResourceValue resValue = mRenderResources.findItemInStyle(style,
-                        attribute.getFirst(), attribute.getSecond());
+                ResourceValue resValue;
+                if (style != null) {
+                    resValue = mRenderResources.findItemInStyle(style, attribute.getFirst(),
+                            attribute.getSecond());
+                } else {
+                    resValue = mRenderResources.findItemInTheme(attribute.getFirst(),
+                            attribute.getSecond());
+                }
 
                 if (resValue != null) {
                     // resolve it to make sure there are no references left.
@@ -756,7 +774,6 @@
         return ta;
     }
 
-
     /**
      * The input int[] attrs is a list of attributes. The returns a list of information about
      * each attributes. The information is (name, isFramework)
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java
index 281337c..908fc47 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java
@@ -28,7 +28,7 @@
 public class BridgePowerManager implements IPowerManager {
 
     @Override
-    public boolean isScreenOn() throws RemoteException {
+    public boolean isInteractive() throws RemoteException {
         return true;
     }
 
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java
index df576d2..d32f6ee 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java
@@ -58,11 +58,6 @@
     }
 
     @Override
-    public void dispatchScreenState(boolean on) throws RemoteException {
-        // pass for now.
-    }
-
-    @Override
     public void windowFocusChanged(boolean arg0, boolean arg1) throws RemoteException {
         // pass for now.
     }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/ActionBarLayout.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/ActionBarLayout.java
new file mode 100644
index 0000000..0e39a57
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/ActionBarLayout.java
@@ -0,0 +1,384 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.layoutlib.bridge.bars;
+
+import com.android.annotations.NonNull;
+import com.android.annotations.Nullable;
+import com.android.ide.common.rendering.api.ActionBarCallback;
+import com.android.ide.common.rendering.api.ActionBarCallback.HomeButtonStyle;
+import com.android.ide.common.rendering.api.RenderResources;
+import com.android.ide.common.rendering.api.ResourceValue;
+import com.android.ide.common.rendering.api.SessionParams;
+import com.android.ide.common.rendering.api.SystemViewCookie;
+import com.android.internal.R;
+import com.android.internal.app.ActionBarImpl;
+import com.android.internal.util.Predicate;
+import com.android.internal.view.menu.ActionMenuView;
+import com.android.internal.view.menu.MenuBuilder;
+import com.android.internal.view.menu.MenuBuilderAccessor;
+import com.android.internal.view.menu.MenuItemImpl;
+import com.android.internal.widget.ActionBarAccessor;
+import com.android.internal.widget.ActionBarContainer;
+import com.android.internal.widget.ActionBarView;
+import com.android.layoutlib.bridge.android.BridgeContext;
+import com.android.layoutlib.bridge.impl.ResourceHelper;
+import com.android.resources.ResourceType;
+
+import android.app.ActionBar;
+import android.app.ActionBar.Tab;
+import android.app.ActionBar.TabListener;
+import android.app.FragmentTransaction;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
+import android.util.DisplayMetrics;
+import android.util.TypedValue;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.MenuInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+import android.widget.LinearLayout;
+import android.widget.ListAdapter;
+import android.widget.ListView;
+import android.widget.RelativeLayout;
+
+import java.util.ArrayList;
+
+import static com.android.ide.common.rendering.api.SystemViewCookie.ACTION_BAR_OVERFLOW;
+
+/**
+ * A layout representing the action bar.
+ */
+public class ActionBarLayout extends LinearLayout {
+
+    // Store another reference to the context so that we don't have to cast it repeatedly.
+    @NonNull private final BridgeContext mBridgeContext;
+    @NonNull private final Context mThemedContext;
+
+    @NonNull private final ActionBar mActionBar;
+
+    // Data for Action Bar.
+    @Nullable private final String mIcon;
+    @Nullable private final String mTitle;
+    @Nullable private final String mSubTitle;
+    private final boolean mSplit;
+    private final boolean mShowHomeAsUp;
+    private final int mNavMode;
+
+    // Helper fields.
+    @NonNull private final MenuBuilder mMenuBuilder;
+    private final int mPopupMaxWidth;
+    @NonNull private final RenderResources res;
+    @Nullable private final ActionBarView mActionBarView;
+    @Nullable private FrameLayout mContentRoot;
+    @NonNull private final ActionBarCallback mCallback;
+
+    // A fake parent for measuring views.
+    @Nullable private ViewGroup mMeasureParent;
+
+    public ActionBarLayout(@NonNull BridgeContext context, @NonNull SessionParams params) {
+
+        super(context);
+        setOrientation(LinearLayout.HORIZONTAL);
+        setGravity(Gravity.CENTER_VERTICAL);
+
+        // Inflate action bar layout.
+        LayoutInflater.from(context).inflate(R.layout.screen_action_bar, this,
+                true /*attachToRoot*/);
+        mActionBar = new ActionBarImpl(this);
+
+        // Set contexts.
+        mBridgeContext = context;
+        mThemedContext = mActionBar.getThemedContext();
+
+        // Set data for action bar.
+        mCallback = params.getProjectCallback().getActionBarCallback();
+        mIcon = params.getAppIcon();
+        mTitle = params.getAppLabel();
+        // Split Action Bar when the screen size is narrow and the application requests split action
+        // bar when narrow.
+        mSplit = context.getResources().getBoolean(R.bool.split_action_bar_is_narrow) &&
+                mCallback.getSplitActionBarWhenNarrow();
+        mNavMode = mCallback.getNavigationMode();
+        // TODO: Support Navigation Drawer Indicator.
+        mShowHomeAsUp = mCallback.getHomeButtonStyle() == HomeButtonStyle.SHOW_HOME_AS_UP;
+        mSubTitle = mCallback.getSubTitle();
+
+
+        // Set helper fields.
+        mMenuBuilder = new MenuBuilder(mThemedContext);
+        res = mBridgeContext.getRenderResources();
+        mPopupMaxWidth = Math.max(mBridgeContext.getMetrics().widthPixels / 2,
+                mThemedContext.getResources().getDimensionPixelSize(
+                        R.dimen.config_prefDialogWidth));
+        mActionBarView = (ActionBarView) findViewById(R.id.action_bar);
+        mContentRoot = (FrameLayout) findViewById(android.R.id.content);
+
+        setupActionBar();
+    }
+
+    /**
+     * Sets up the action bar by filling the appropriate data.
+     */
+    private void setupActionBar() {
+        // Add title and sub title.
+        ResourceValue titleValue = res.findResValue(mTitle, false /*isFramework*/);
+        if (titleValue != null && titleValue.getValue() != null) {
+            mActionBar.setTitle(titleValue.getValue());
+        } else {
+            mActionBar.setTitle(mTitle);
+        }
+        if (mSubTitle != null) {
+            mActionBar.setSubtitle(mSubTitle);
+        }
+
+        // Add show home as up icon.
+        if (mShowHomeAsUp) {
+            mActionBar.setDisplayOptions(0xFF, ActionBar.DISPLAY_HOME_AS_UP);
+        }
+
+        // Set the navigation mode.
+        mActionBar.setNavigationMode(mNavMode);
+        if (mNavMode == ActionBar.NAVIGATION_MODE_TABS) {
+            setupTabs(3);
+        }
+
+        if (mActionBarView != null) {
+            // If the action bar style doesn't specify an icon, set the icon obtained from the session
+            // params.
+            if (!mActionBarView.hasIcon() && mIcon != null) {
+                Drawable iconDrawable = getDrawable(mIcon, false /*isFramework*/);
+                if (iconDrawable != null) {
+                    mActionBar.setIcon(iconDrawable);
+                }
+            }
+
+            // Set action bar to be split, if needed.
+            ActionBarContainer splitView = (ActionBarContainer) findViewById(R.id.split_action_bar);
+            mActionBarView.setSplitView(splitView);
+            mActionBarView.setSplitActionBar(mSplit);
+
+            inflateMenus();
+
+            // Find if the Overflow Menu Button (the three dots) exists. If yes,
+            // add the view cookie.
+            Predicate<View> overflowMenuButtonTest = new Predicate<View>() {
+                @Override
+                public boolean apply(View view) {
+                    ViewGroup.LayoutParams lp = view.getLayoutParams();
+                    return lp instanceof ActionMenuView.LayoutParams &&
+                            ((ActionMenuView.LayoutParams) lp).isOverflowButton;
+                }
+            };
+            View overflowMenu = null;
+            if (mSplit) {
+                if (splitView != null) {
+                    overflowMenu = splitView.findViewByPredicate(overflowMenuButtonTest);
+                }
+            }
+            else {
+                overflowMenu = mActionBarView.findViewByPredicate(overflowMenuButtonTest);
+            }
+            if (overflowMenu != null) {
+                mBridgeContext.addViewKey(overflowMenu, new SystemViewCookie(ACTION_BAR_OVERFLOW));
+            }
+        }
+    }
+
+    /**
+     * Gets the menus to add to the action bar from the callback, resolves them, inflates them and
+     * adds them to the action bar.
+     */
+    private void inflateMenus() {
+        if (mActionBarView == null) {
+            return;
+        }
+        final MenuInflater inflater = new MenuInflater(mThemedContext);
+        for (String name : mCallback.getMenuIdNames()) {
+            if (mBridgeContext.getRenderResources().getProjectResource(ResourceType.MENU, name)
+                    != null) {
+                int id = mBridgeContext.getProjectResourceValue(ResourceType.MENU, name, -1);
+                if (id > -1) {
+                    inflater.inflate(id, mMenuBuilder);
+                }
+            }
+        }
+        mActionBarView.setMenu(mMenuBuilder, null /*callback*/);
+    }
+
+    // TODO: Use an adapter, like List View to set up tabs.
+    private void setupTabs(int num) {
+        for (int i = 1; i <= num; i++) {
+            Tab tab = mActionBar.newTab().setText("Tab" + i).setTabListener(new TabListener() {
+                @Override
+                public void onTabUnselected(Tab t, FragmentTransaction ft) {
+                    // pass
+                }
+                @Override
+                public void onTabSelected(Tab t, FragmentTransaction ft) {
+                    // pass
+                }
+                @Override
+                public void onTabReselected(Tab t, FragmentTransaction ft) {
+                    // pass
+                }
+            });
+            mActionBar.addTab(tab);
+        }
+    }
+
+    @Nullable
+    private Drawable getDrawable(@NonNull String name, boolean isFramework) {
+        ResourceValue value = res.findResValue(name, isFramework);
+        value = res.resolveResValue(value);
+        if (value != null) {
+            return ResourceHelper.getDrawable(value, mBridgeContext);
+        }
+        return null;
+    }
+
+    /**
+     * Creates a Popup and adds it to the content frame. It also adds another {@link FrameLayout} to
+     * the content frame which shall serve as the new content root.
+     */
+    public void createMenuPopup() {
+        assert mContentRoot != null && findViewById(android.R.id.content) == mContentRoot
+                : "Action Bar Menus have already been created.";
+
+        if (!isOverflowPopupNeeded()) {
+            return;
+        }
+
+        // Create a layout to hold the menus and the user's content.
+        RelativeLayout layout = new RelativeLayout(mThemedContext);
+        layout.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
+                LayoutParams.MATCH_PARENT));
+        mContentRoot.addView(layout);
+        // Create a layout for the user's content.
+        FrameLayout contentRoot = new FrameLayout(mBridgeContext);
+        contentRoot.setLayoutParams(new LayoutParams(
+                LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
+        // Add contentRoot and menus to the layout.
+        layout.addView(contentRoot);
+        layout.addView(createMenuView());
+        // ContentRoot is now the view we just created.
+        mContentRoot = contentRoot;
+    }
+
+    /**
+     * Returns a {@link LinearLayout} containing the menu list view to be embedded in a
+     * {@link RelativeLayout}
+     */
+    @NonNull
+    private View createMenuView() {
+        DisplayMetrics metrics = mBridgeContext.getMetrics();
+        OverflowMenuAdapter adapter = new OverflowMenuAdapter(mMenuBuilder, mThemedContext);
+
+        LinearLayout layout = new LinearLayout(mThemedContext);
+        RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(
+                measureContentWidth(adapter), LayoutParams.WRAP_CONTENT);
+        layoutParams.addRule(RelativeLayout.ALIGN_PARENT_END);
+        if (mSplit) {
+            layoutParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
+            // TODO: Find correct value instead of hardcoded 10dp.
+            layoutParams.bottomMargin = getPixelValue("-10dp", metrics);
+        } else {
+            layoutParams.topMargin = getPixelValue("-10dp", metrics);
+        }
+        layout.setLayoutParams(layoutParams);
+        final TypedArray a = mThemedContext.obtainStyledAttributes(null,
+                R.styleable.PopupWindow, R.attr.popupMenuStyle, 0);
+        layout.setBackground(a.getDrawable(R.styleable.PopupWindow_popupBackground));
+        layout.setDividerDrawable(a.getDrawable(R.attr.actionBarDivider));
+        a.recycle();
+        layout.setOrientation(LinearLayout.VERTICAL);
+        layout.setDividerPadding(getPixelValue("12dp", metrics));
+        layout.setShowDividers(LinearLayout.SHOW_DIVIDER_MIDDLE);
+
+        ListView listView = new ListView(mThemedContext, null, R.attr.dropDownListViewStyle);
+        listView.setAdapter(adapter);
+        layout.addView(listView);
+        return layout;
+    }
+
+    private boolean isOverflowPopupNeeded() {
+        boolean needed = mCallback.isOverflowPopupNeeded();
+        if (!needed) {
+            return false;
+        }
+        // Copied from android.widget.ActionMenuPresenter.updateMenuView()
+        ArrayList<MenuItemImpl> menus = MenuBuilderAccessor.getNonActionItems(mMenuBuilder);
+        if (ActionBarAccessor.getActionMenuPresenter(mActionBarView).isOverflowReserved() &&
+                menus != null) {
+            final int count = menus.size();
+            if (count == 1) {
+                needed = !menus.get(0).isActionViewExpanded();
+            } else {
+                needed = count > 0;
+            }
+        }
+        return needed;
+    }
+
+    @Nullable
+    public FrameLayout getContentRoot() {
+        return mContentRoot;
+    }
+
+    // Copied from com.android.internal.view.menu.MenuPopHelper.measureContentWidth()
+    private int measureContentWidth(@NonNull ListAdapter adapter) {
+        // Menus don't tend to be long, so this is more sane than it looks.
+        int maxWidth = 0;
+        View itemView = null;
+        int itemType = 0;
+
+        final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+        final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+        final int count = adapter.getCount();
+        for (int i = 0; i < count; i++) {
+            final int positionType = adapter.getItemViewType(i);
+            if (positionType != itemType) {
+                itemType = positionType;
+                itemView = null;
+            }
+
+            if (mMeasureParent == null) {
+                mMeasureParent = new FrameLayout(mThemedContext);
+            }
+
+            itemView = adapter.getView(i, itemView, mMeasureParent);
+            itemView.measure(widthMeasureSpec, heightMeasureSpec);
+
+            final int itemWidth = itemView.getMeasuredWidth();
+            if (itemWidth >= mPopupMaxWidth) {
+                return mPopupMaxWidth;
+            } else if (itemWidth > maxWidth) {
+                maxWidth = itemWidth;
+            }
+        }
+
+        return maxWidth;
+    }
+
+    private int getPixelValue(@NonNull String value, @NonNull DisplayMetrics metrics) {
+        TypedValue typedValue = ResourceHelper.getValue(null, value, false /*requireUnit*/);
+        return (int) typedValue.getDimension(metrics);
+    }
+
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/FakeActionBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/FakeActionBar.java
deleted file mode 100644
index 226649d..0000000
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/FakeActionBar.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR 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.layoutlib.bridge.bars;
-
-import com.android.resources.Density;
-
-import org.xmlpull.v1.XmlPullParserException;
-
-import android.content.Context;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-public class FakeActionBar extends CustomBar {
-
-    private TextView mTextView;
-
-    public FakeActionBar(Context context, Density density, String label, String icon)
-            throws XmlPullParserException {
-        super(context, density, LinearLayout.HORIZONTAL, "/bars/action_bar.xml", "action_bar.xml");
-
-        // Cannot access the inside items through id because no R.id values have been
-        // created for them.
-        // We do know the order though.
-        loadIconById(android.R.id.home, icon);
-        mTextView = setText(1, label);
-
-        setStyle("actionBarStyle");
-    }
-
-    @Override
-    protected TextView getStyleableTextView() {
-        return mTextView;
-    }
-}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/OverflowMenuAdapter.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/OverflowMenuAdapter.java
new file mode 100644
index 0000000..79e231c
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/OverflowMenuAdapter.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.layoutlib.bridge.bars;
+
+import com.android.internal.view.menu.MenuBuilder;
+import com.android.internal.view.menu.MenuBuilderAccessor;
+import com.android.internal.view.menu.MenuItemImpl;
+import com.android.internal.view.menu.MenuView;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+
+import java.util.ArrayList;
+
+/**
+ * Provides an adapter for Overflow menu popup. This is very similar to
+ * {@code MenuPopupHelper.MenuAdapter}
+ */
+public class OverflowMenuAdapter extends BaseAdapter {
+
+    private final MenuBuilder mMenu;
+    private int mExpandedIndex = -1;
+    private final Context context;
+
+    public OverflowMenuAdapter(MenuBuilder menu, Context context) {
+        mMenu = menu;
+        findExpandedIndex();
+        this.context = context;
+    }
+
+    @Override
+    public int getCount() {
+        ArrayList<MenuItemImpl> items = MenuBuilderAccessor.getNonActionItems(mMenu);
+        if (mExpandedIndex < 0) {
+            return items.size();
+        }
+        return items.size() - 1;
+    }
+
+    @Override
+    public MenuItemImpl getItem(int position) {
+        ArrayList<MenuItemImpl> items = MenuBuilderAccessor.getNonActionItems(mMenu);
+        if (mExpandedIndex >= 0 && position >= mExpandedIndex) {
+            position++;
+        }
+        return items.get(position);
+    }
+
+    @Override
+    public long getItemId(int position) {
+        // Since a menu item's ID is optional, we'll use the position as an
+        // ID for the item in the AdapterView
+        return position;
+    }
+
+    @Override
+    public View getView(int position, View convertView, ViewGroup parent) {
+        if (convertView == null) {
+            LayoutInflater mInflater = LayoutInflater.from(context);
+            convertView = mInflater.inflate(com.android.internal.R.layout.popup_menu_item_layout,
+                    parent, false);
+        }
+
+        MenuView.ItemView itemView = (MenuView.ItemView) convertView;
+        itemView.initialize(getItem(position), 0);
+        return convertView;
+    }
+
+    private void findExpandedIndex() {
+        final MenuItemImpl expandedItem = mMenu.getExpandedItem();
+        if (expandedItem != null) {
+            final ArrayList<MenuItemImpl> items = MenuBuilderAccessor.getNonActionItems(mMenu);
+            final int count = items.size();
+            for (int i = 0; i < count; i++) {
+                final MenuItemImpl item = items.get(i);
+                if (item == expandedItem) {
+                    mExpandedIndex = i;
+                    return;
+                }
+            }
+        }
+    }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
index 377d996..4af73cf 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
@@ -28,7 +28,6 @@
 import com.android.ide.common.rendering.api.IAnimationListener;
 import com.android.ide.common.rendering.api.ILayoutPullParser;
 import com.android.ide.common.rendering.api.IProjectCallback;
-import com.android.ide.common.rendering.api.RenderParams;
 import com.android.ide.common.rendering.api.RenderResources;
 import com.android.ide.common.rendering.api.RenderSession;
 import com.android.ide.common.rendering.api.ResourceReference;
@@ -39,16 +38,23 @@
 import com.android.ide.common.rendering.api.SessionParams.RenderingMode;
 import com.android.ide.common.rendering.api.ViewInfo;
 import com.android.internal.util.XmlUtils;
+import com.android.internal.view.menu.ActionMenuItemView;
+import com.android.internal.view.menu.BridgeMenuItemImpl;
+import com.android.internal.view.menu.IconMenuItemView;
+import com.android.internal.view.menu.ListMenuItemView;
+import com.android.internal.view.menu.MenuItemImpl;
+import com.android.internal.view.menu.MenuView;
 import com.android.layoutlib.bridge.Bridge;
 import com.android.layoutlib.bridge.android.BridgeContext;
 import com.android.layoutlib.bridge.android.BridgeLayoutParamsMapAttributes;
 import com.android.layoutlib.bridge.android.BridgeXmlBlockParser;
-import com.android.layoutlib.bridge.bars.FakeActionBar;
 import com.android.layoutlib.bridge.bars.NavigationBar;
 import com.android.layoutlib.bridge.bars.StatusBar;
 import com.android.layoutlib.bridge.bars.TitleBar;
+import com.android.layoutlib.bridge.bars.ActionBarLayout;
 import com.android.layoutlib.bridge.impl.binding.FakeAdapter;
 import com.android.layoutlib.bridge.impl.binding.FakeExpandableAdapter;
+import com.android.resources.Density;
 import com.android.resources.ResourceType;
 import com.android.resources.ScreenOrientation;
 import com.android.util.Pair;
@@ -100,11 +106,10 @@
 
 /**
  * Class implementing the render session.
- *
+ * <p/>
  * A session is a stateful representation of a layout file. It is initialized with data coming
  * through the {@link Bridge} API to inflate the layout. Further actions and rendering can then
  * be done on the layout.
- *
  */
 public class RenderSessionImpl extends RenderAction<SessionParams> {
 
@@ -134,6 +139,7 @@
     // information being returned through the API
     private BufferedImage mImage;
     private List<ViewInfo> mViewInfoList;
+    private List<ViewInfo> mSystemViewInfoList;
 
     private static final class PostInflateException extends Exception {
         private static final long serialVersionUID = 1L;
@@ -146,10 +152,11 @@
     /**
      * Creates a layout scene with all the information coming from the layout bridge API.
      * <p>
-     * This <b>must</b> be followed by a call to {@link RenderSessionImpl#init()}, which act as a
+     * This <b>must</b> be followed by a call to {@link RenderSessionImpl#init(long)},
+     * which act as a
      * call to {@link RenderSessionImpl#acquire(long)}
      *
-     * @see LayoutBridge#createScene(com.android.layoutlib.api.SceneParams)
+     * @see Bridge#createSession(SessionParams)
      */
     public RenderSessionImpl(SessionParams params) {
         super(new SessionParams(params));
@@ -169,13 +176,14 @@
     @Override
     public Result init(long timeout) {
         Result result = super.init(timeout);
-        if (result.isSuccess() == false) {
+        if (!result.isSuccess()) {
             return result;
         }
 
         SessionParams params = getParams();
         BridgeContext context = getContext();
 
+
         RenderResources resources = getParams().getResources();
         DisplayMetrics metrics = getContext().getMetrics();
 
@@ -193,6 +201,7 @@
 
         // FIXME: find those out, and possibly add them to the render params
         boolean hasNavigationBar = true;
+        //noinspection ConstantConditions
         IWindowManager iwm = new IWindowManagerImpl(getContext().getConfiguration(),
                 metrics, Surface.ROTATION_0,
                 hasNavigationBar);
@@ -225,14 +234,14 @@
             HardwareConfig hardwareConfig = params.getHardwareConfig();
             BridgeContext context = getContext();
             boolean isRtl = Bridge.isLocaleRtl(params.getLocale());
-            int direction = isRtl ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR;
+            int layoutDirection = isRtl ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR;
 
             // the view group that receives the window background.
-            ViewGroup backgroundView = null;
+            ViewGroup backgroundView;
 
             if (mWindowIsFloating || params.isForceNoDecor()) {
                 backgroundView = mViewRoot = mContentRoot = new FrameLayout(context);
-                mViewRoot.setLayoutDirection(direction);
+                mViewRoot.setLayoutDirection(layoutDirection);
             } else {
                 if (hasSoftwareButtons() && mNavigationBarOrientation == LinearLayout.VERTICAL) {
                     /*
@@ -254,20 +263,15 @@
                        the bottom
                      */
                     LinearLayout topLayout = new LinearLayout(context);
-                    topLayout.setLayoutDirection(direction);
+                    topLayout.setLayoutDirection(layoutDirection);
                     mViewRoot = topLayout;
                     topLayout.setOrientation(LinearLayout.HORIZONTAL);
 
                     try {
-                        NavigationBar navigationBar = new NavigationBar(context,
-                                hardwareConfig.getDensity(), LinearLayout.VERTICAL, isRtl,
-                                params.isRtlSupported());
-                        navigationBar.setLayoutParams(
-                                new LinearLayout.LayoutParams(
-                                        mNavigationBarSize,
-                                        LayoutParams.MATCH_PARENT));
+                        NavigationBar navigationBar = createNavigationBar(context,
+                                hardwareConfig.getDensity(), isRtl, params.isRtlSupported());
                         topLayout.addView(navigationBar);
-                    } catch (XmlPullParserException e) {
+                    } catch (XmlPullParserException ignored) {
 
                     }
                 }
@@ -293,14 +297,15 @@
 
                 LinearLayout topLayout = new LinearLayout(context);
                 topLayout.setOrientation(LinearLayout.VERTICAL);
-                topLayout.setLayoutDirection(direction);
+                topLayout.setLayoutDirection(layoutDirection);
                 // if we don't already have a view root this is it
                 if (mViewRoot == null) {
                     mViewRoot = topLayout;
                 } else {
+                    int topLayoutWidth =
+                            params.getHardwareConfig().getScreenWidth() - mNavigationBarSize;
                     LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
-                            LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
-                    layoutParams.weight = 1;
+                            topLayoutWidth, LayoutParams.MATCH_PARENT);
                     topLayout.setLayoutParams(layoutParams);
 
                     // this is the case of soft buttons + vertical bar.
@@ -319,13 +324,10 @@
                 if (mStatusBarSize > 0) {
                     // system bar
                     try {
-                        StatusBar systemBar = new StatusBar(context, hardwareConfig.getDensity(),
-                                direction, params.isRtlSupported());
-                        systemBar.setLayoutParams(
-                                new LinearLayout.LayoutParams(
-                                        LayoutParams.MATCH_PARENT, mStatusBarSize));
-                        topLayout.addView(systemBar);
-                    } catch (XmlPullParserException e) {
+                        StatusBar statusBar = createStatusBar(context, hardwareConfig.getDensity(),
+                                layoutDirection, params.isRtlSupported());
+                        topLayout.addView(statusBar);
+                    } catch (XmlPullParserException ignored) {
 
                     }
                 }
@@ -342,50 +344,38 @@
 
                 // if the theme says no title/action bar, then the size will be 0
                 if (mActionBarSize > 0) {
-                    try {
-                        FakeActionBar actionBar = new FakeActionBar(context,
-                                hardwareConfig.getDensity(),
-                                params.getAppLabel(), params.getAppIcon());
-                        actionBar.setLayoutParams(
-                                new LinearLayout.LayoutParams(
-                                        LayoutParams.MATCH_PARENT, mActionBarSize));
-                        backgroundLayout.addView(actionBar);
-                    } catch (XmlPullParserException e) {
-
-                    }
+                    ActionBarLayout actionBar = createActionBar(context, params);
+                    backgroundLayout.addView(actionBar);
+                    actionBar.createMenuPopup();
+                    mContentRoot = actionBar.getContentRoot();
                 } else if (mTitleBarSize > 0) {
                     try {
-                        TitleBar titleBar = new TitleBar(context,
+                        TitleBar titleBar = createTitleBar(context,
                                 hardwareConfig.getDensity(), params.getAppLabel());
-                        titleBar.setLayoutParams(
-                                new LinearLayout.LayoutParams(
-                                        LayoutParams.MATCH_PARENT, mTitleBarSize));
                         backgroundLayout.addView(titleBar);
-                    } catch (XmlPullParserException e) {
+                    } catch (XmlPullParserException ignored) {
 
                     }
                 }
 
                 // content frame
-                mContentRoot = new FrameLayout(context);
-                layoutParams = new LinearLayout.LayoutParams(
-                        LayoutParams.MATCH_PARENT, 0);
-                layoutParams.weight = 1;
-                mContentRoot.setLayoutParams(layoutParams);
-                backgroundLayout.addView(mContentRoot);
+                if (mContentRoot == null) {
+                    mContentRoot = new FrameLayout(context);
+                    layoutParams = new LinearLayout.LayoutParams(
+                            LayoutParams.MATCH_PARENT, 0);
+                    layoutParams.weight = 1;
+                    mContentRoot.setLayoutParams(layoutParams);
+                    backgroundLayout.addView(mContentRoot);
+                }
 
                 if (mNavigationBarOrientation == LinearLayout.HORIZONTAL &&
                         mNavigationBarSize > 0) {
                     // system bar
                     try {
-                        NavigationBar navigationBar = new NavigationBar(context,
-                                hardwareConfig.getDensity(), LinearLayout.HORIZONTAL, isRtl,
-                                params.isRtlSupported());
-                        navigationBar.setLayoutParams(
-                                new LinearLayout.LayoutParams(
-                                        LayoutParams.MATCH_PARENT, mNavigationBarSize));
+                        NavigationBar navigationBar = createNavigationBar(context,
+                                hardwareConfig.getDensity(), isRtl, params.isRtlSupported());
                         topLayout.addView(navigationBar);
-                    } catch (XmlPullParserException e) {
+                    } catch (XmlPullParserException ignored) {
 
                     }
                 }
@@ -410,7 +400,7 @@
             postInflateProcess(view, params.getProjectCallback());
 
             // get the background drawable
-            if (mWindowBackground != null && backgroundView != null) {
+            if (mWindowBackground != null) {
                 Drawable d = ResourceHelper.getDrawable(mWindowBackground, context);
                 backgroundView.setBackground(d);
             }
@@ -441,7 +431,7 @@
      * @throws IllegalStateException if the current context is different than the one owned by
      *      the scene, or if {@link #acquire(long)} was not called.
      *
-     * @see RenderParams#getRenderingMode()
+     * @see SessionParams#getRenderingMode()
      * @see RenderSession#render(long)
      */
     public Result render(boolean freshRender) {
@@ -487,6 +477,7 @@
 
                     // first measure the full layout, with EXACTLY to get the size of the
                     // content as it is inside the decor/dialog
+                    @SuppressWarnings("deprecation")
                     Pair<Integer, Integer> exactMeasure = measureView(
                             mViewRoot, mContentRoot.getChildAt(0),
                             mMeasuredScreenWidth, MeasureSpec.EXACTLY,
@@ -494,6 +485,7 @@
 
                     // now measure the content only using UNSPECIFIED (where applicable, based on
                     // the rendering mode). This will give us the size the content needs.
+                    @SuppressWarnings("deprecation")
                     Pair<Integer, Integer> result = measureView(
                             mContentRoot, mContentRoot.getChildAt(0),
                             mMeasuredScreenWidth, widthMeasureSpecMode,
@@ -569,7 +561,7 @@
                     mCanvas.setDensity(hardwareConfig.getDensity().getDpiValue());
                 }
 
-                if (freshRender && newImage == false) {
+                if (freshRender && !newImage) {
                     Graphics2D gc = mImage.createGraphics();
                     gc.setComposite(AlphaComposite.Src);
 
@@ -584,7 +576,8 @@
                 mViewRoot.draw(mCanvas);
             }
 
-            mViewInfoList = startVisitingViews(mViewRoot, 0, params.getExtendedViewInfoMode());
+            mSystemViewInfoList = visitAllChildren(mViewRoot, 0, params.getExtendedViewInfoMode(),
+                    false);
 
             // success!
             return SUCCESS.createResult();
@@ -614,6 +607,7 @@
      * @param heightMode the MeasureSpec mode to use for the height.
      * @return the measured width/height if measuredView is non-null, null otherwise.
      */
+    @SuppressWarnings("deprecation")  // For the use of Pair
     private Pair<Integer, Integer> measureView(ViewGroup viewToMeasure, View measuredView,
             int width, int widthMode, int height, int heightMode) {
         int w_spec = MeasureSpec.makeMeasureSpec(width, widthMode);
@@ -644,7 +638,7 @@
         BridgeContext context = getContext();
 
         // find the animation file.
-        ResourceValue animationResource = null;
+        ResourceValue animationResource;
         int animationId = 0;
         if (isFrameworkAnimation) {
             animationResource = context.getRenderResources().getFrameworkResource(
@@ -734,7 +728,7 @@
 
         // add it to the parentView in the correct location
         Result result = addView(parentView, child, index);
-        if (result.isSuccess() == false) {
+        if (!result.isSuccess()) {
             return result;
         }
 
@@ -804,13 +798,13 @@
                     public void run() {
                         Result result = moveView(previousParent, newParentView, childView, index,
                                 params);
-                        if (result.isSuccess() == false) {
+                        if (!result.isSuccess()) {
                             listener.done(result);
                         }
 
                         // ready to do the work, acquire the scene.
                         result = acquire(250);
-                        if (result.isSuccess() == false) {
+                        if (!result.isSuccess()) {
                             listener.done(result);
                             return;
                         }
@@ -868,7 +862,7 @@
         }
 
         Result result = moveView(previousParent, newParentView, childView, index, layoutParams);
-        if (result.isSuccess() == false) {
+        if (!result.isSuccess()) {
             return result;
         }
 
@@ -1002,7 +996,7 @@
         }
 
         Result result = removeView(parent, childView);
-        if (result.isSuccess() == false) {
+        if (!result.isSuccess()) {
             return result;
         }
 
@@ -1030,7 +1024,7 @@
 
 
     private void findBackground(RenderResources resources) {
-        if (getParams().isBgColorOverridden() == false) {
+        if (!getParams().isBgColorOverridden()) {
             mWindowBackground = resources.findItemInTheme("windowBackground",
                     true /*isFrameworkAttr*/);
             if (mWindowBackground != null) {
@@ -1047,7 +1041,7 @@
         boolean windowFullscreen = getBooleanThemeValue(resources,
                 "windowFullscreen", false /*defaultValue*/);
 
-        if (windowFullscreen == false && mWindowIsFloating == false) {
+        if (!windowFullscreen && !mWindowIsFloating) {
             // default value
             mStatusBarSize = DEFAULT_STATUS_BAR_HEIGHT;
 
@@ -1101,7 +1095,7 @@
             boolean windowNoTitle = getBooleanThemeValue(resources,
                     "windowNoTitle", false /*defaultValue*/);
 
-            if (windowNoTitle == false) {
+            if (!windowNoTitle) {
 
                 // default size of the window title bar
                 mTitleBarSize = DEFAULT_TITLE_BAR_HEIGHT;
@@ -1128,7 +1122,7 @@
     }
 
     private void findNavigationBar(RenderResources resources, DisplayMetrics metrics) {
-        if (hasSoftwareButtons() && mWindowIsFloating == false) {
+        if (hasSoftwareButtons() && !mWindowIsFloating) {
 
             // default value
             mNavigationBarSize = 48; // ??
@@ -1142,15 +1136,12 @@
                 int shortSize = hardwareConfig.getScreenHeight();
 
                 // compute in dp
-                int shortSizeDp = shortSize * DisplayMetrics.DENSITY_DEFAULT / hardwareConfig.getDensity().getDpiValue();
+                int shortSizeDp = shortSize * DisplayMetrics.DENSITY_DEFAULT /
+                        hardwareConfig.getDensity().getDpiValue();
 
-                if (shortSizeDp < 600) {
-                    // 0-599dp: "phone" UI with bar on the side
-                    barOnBottom = false;
-                } else {
-                    // 600+dp: "tablet" UI with bar on the bottom
-                    barOnBottom = true;
-                }
+                // 0-599dp: "phone" UI with bar on the side
+                // 600+dp: "tablet" UI with bar on the bottom
+                barOnBottom = shortSizeDp >= 600;
             }
 
             if (barOnBottom) {
@@ -1201,13 +1192,15 @@
     }
 
     /**
-     * Post process on a view hierachy that was just inflated.
-     * <p/>At the moment this only support TabHost: If {@link TabHost} is detected, look for the
+     * Post process on a view hierarchy that was just inflated.
+     * <p/>
+     * At the moment this only supports TabHost: If {@link TabHost} is detected, look for the
      * {@link TabWidget}, and the corresponding {@link FrameLayout} and make new tabs automatically
      * based on the content of the {@link FrameLayout}.
      * @param view the root view to process.
      * @param projectCallback callback to the project.
      */
+    @SuppressWarnings("deprecation")  // For the use of Pair
     private void postInflateProcess(View view, IProjectCallback projectCallback)
             throws PostInflateException {
         if (view instanceof TabHost) {
@@ -1310,7 +1303,7 @@
                     "TabHost requires a TabWidget with id \"android:id/tabs\".\n");
         }
 
-        if ((v instanceof TabWidget) == false) {
+        if (!(v instanceof TabWidget)) {
             throw new PostInflateException(String.format(
                     "TabHost requires a TabWidget with id \"android:id/tabs\".\n" +
                     "View found with id 'tabs' is '%s'", v.getClass().getCanonicalName()));
@@ -1319,12 +1312,14 @@
         v = tabHost.findViewById(android.R.id.tabcontent);
 
         if (v == null) {
-            // TODO: see if we can fake tabs even without the FrameLayout (same below when the framelayout is empty)
+            // TODO: see if we can fake tabs even without the FrameLayout (same below when the frameLayout is empty)
+            //noinspection SpellCheckingInspection
             throw new PostInflateException(
                     "TabHost requires a FrameLayout with id \"android:id/tabcontent\".");
         }
 
-        if ((v instanceof FrameLayout) == false) {
+        if (!(v instanceof FrameLayout)) {
+            //noinspection SpellCheckingInspection
             throw new PostInflateException(String.format(
                     "TabHost requires a FrameLayout with id \"android:id/tabcontent\".\n" +
                     "View found with id 'tabcontent' is '%s'", v.getClass().getCanonicalName()));
@@ -1332,7 +1327,7 @@
 
         FrameLayout content = (FrameLayout)v;
 
-        // now process the content of the framelayout and dynamically create tabs for it.
+        // now process the content of the frameLayout and dynamically create tabs for it.
         final int count = content.getChildCount();
 
         // this must be called before addTab() so that the TabHost searches its TabWidget
@@ -1350,13 +1345,13 @@
                         }
                     });
             tabHost.addTab(spec);
-            return;
         } else {
-            // for each child of the framelayout, add a new TabSpec
+            // for each child of the frameLayout, add a new TabSpec
             for (int i = 0 ; i < count ; i++) {
                 View child = content.getChildAt(i);
                 String tabSpec = String.format("tab_spec%d", i+1);
                 int id = child.getId();
+                @SuppressWarnings("deprecation")
                 Pair<ResourceType, String> resource = projectCallback.resolveResourceId(id);
                 String name;
                 if (resource != null) {
@@ -1369,50 +1364,126 @@
         }
     }
 
-    private List<ViewInfo> startVisitingViews(View view, int offset, boolean setExtendedInfo) {
-        if (view == null) {
-            return null;
-        }
-
-        // adjust the offset to this view.
-        offset += view.getTop();
-
-        if (view == mContentRoot) {
-            return visitAllChildren(mContentRoot, offset, setExtendedInfo);
-        }
-
-        // otherwise, look for mContentRoot in the children
-        if (view instanceof ViewGroup) {
-            ViewGroup group = ((ViewGroup) view);
-
-            for (int i = 0; i < group.getChildCount(); i++) {
-                List<ViewInfo> list = startVisitingViews(group.getChildAt(i), offset,
-                        setExtendedInfo);
-                if (list != null) {
-                    return list;
-                }
-            }
-        }
-
-        return null;
-    }
-
     /**
-     * Visits a View and its children and generate a {@link ViewInfo} containing the
+     * Visits a {@link View} and its children and generate a {@link ViewInfo} containing the
      * bounds of all the views.
+     *
      * @param view the root View
      * @param offset an offset for the view bounds.
      * @param setExtendedInfo whether to set the extended view info in the {@link ViewInfo} object.
+     * @param isContentFrame {@code true} if the {@code ViewInfo} to be created is part of the
+     *                       content frame.
+     *
+     * @return {@code ViewInfo} containing the bounds of the view and it children otherwise.
      */
-    private ViewInfo visit(View view, int offset, boolean setExtendedInfo) {
+    private ViewInfo visit(View view, int offset, boolean setExtendedInfo,
+            boolean isContentFrame) {
+        ViewInfo result = createViewInfo(view, offset, setExtendedInfo, isContentFrame);
+
+        if (view instanceof ViewGroup) {
+            ViewGroup group = ((ViewGroup) view);
+            result.setChildren(visitAllChildren(group, isContentFrame ? 0 : offset,
+                    setExtendedInfo, isContentFrame));
+        }
+        return result;
+    }
+
+    /**
+     * Visits all the children of a given ViewGroup and generates a list of {@link ViewInfo}
+     * containing the bounds of all the views. It also initializes the {@link #mViewInfoList} with
+     * the children of the {@code mContentRoot}.
+     *
+     * @param viewGroup the root View
+     * @param offset an offset from the top for the content view frame.
+     * @param setExtendedInfo whether to set the extended view info in the {@link ViewInfo} object.
+     * @param isContentFrame {@code true} if the {@code ViewInfo} to be created is part of the
+     *                       content frame. {@code false} if the {@code ViewInfo} to be created is
+     *                       part of the system decor.
+     */
+    private List<ViewInfo> visitAllChildren(ViewGroup viewGroup, int offset,
+            boolean setExtendedInfo, boolean isContentFrame) {
+        if (viewGroup == null) {
+            return null;
+        }
+
+        if (!isContentFrame) {
+            offset += viewGroup.getTop();
+        }
+
+        int childCount = viewGroup.getChildCount();
+        if (viewGroup == mContentRoot) {
+            List<ViewInfo> childrenWithoutOffset = new ArrayList<ViewInfo>(childCount);
+            List<ViewInfo> childrenWithOffset = new ArrayList<ViewInfo>(childCount);
+            for (int i = 0; i < childCount; i++) {
+                ViewInfo[] childViewInfo = visitContentRoot(viewGroup.getChildAt(i), offset,
+                        setExtendedInfo);
+                childrenWithoutOffset.add(childViewInfo[0]);
+                childrenWithOffset.add(childViewInfo[1]);
+            }
+            mViewInfoList = childrenWithOffset;
+            return childrenWithoutOffset;
+        } else {
+            List<ViewInfo> children = new ArrayList<ViewInfo>(childCount);
+            for (int i = 0; i < childCount; i++) {
+                children.add(visit(viewGroup.getChildAt(i), offset, setExtendedInfo,
+                        isContentFrame));
+            }
+            return children;
+        }
+    }
+
+    /**
+     * Visits the children of {@link #mContentRoot} and generates {@link ViewInfo} containing the
+     * bounds of all the views. It returns two {@code ViewInfo} objects with the same children,
+     * one with the {@code offset} and other without the {@code offset}. The offset is needed to
+     * get the right bounds if the {@code ViewInfo} hierarchy is accessed from
+     * {@code mViewInfoList}. When the hierarchy is accessed via {@code mSystemViewInfoList}, the
+     * offset is not needed.
+     *
+     * @return an array of length two, with ViewInfo at index 0 is without offset and ViewInfo at
+     *         index 1 is with the offset.
+     */
+    private ViewInfo[] visitContentRoot(View view, int offset, boolean setExtendedInfo) {
+        ViewInfo[] result = new ViewInfo[2];
+        if (view == null) {
+            return result;
+        }
+
+        result[0] = createViewInfo(view, 0, setExtendedInfo, true);
+        result[1] = createViewInfo(view, offset, setExtendedInfo, true);
+        if (view instanceof ViewGroup) {
+            List<ViewInfo> children = visitAllChildren((ViewGroup) view, 0, setExtendedInfo, true);
+            result[0].setChildren(children);
+            result[1].setChildren(children);
+        }
+        return result;
+    }
+
+    /**
+     * Creates a {@link ViewInfo} for the view. The {@code ViewInfo} corresponding to the children
+     * of the {@code view} are not created. Consequently, the children of {@code ViewInfo} is not
+     * set.
+     * @param offset an offset for the view bounds. Used only if view is part of the content frame.
+     */
+    private ViewInfo createViewInfo(View view, int offset, boolean setExtendedInfo,
+            boolean isContentFrame) {
         if (view == null) {
             return null;
         }
 
-        ViewInfo result = new ViewInfo(view.getClass().getName(),
-                getContext().getViewKey(view),
-                view.getLeft(), view.getTop() + offset, view.getRight(), view.getBottom() + offset,
-                view, view.getLayoutParams());
+        ViewInfo result;
+        if (isContentFrame) {
+            result = new ViewInfo(view.getClass().getName(),
+                    getViewKey(view),
+                    view.getLeft(), view.getTop() + offset, view.getRight(),
+                    view.getBottom() + offset, view, view.getLayoutParams());
+
+        } else {
+            result = new SystemViewInfo(view.getClass().getName(),
+                    getViewKey(view),
+                    view.getLeft(), view.getTop(), view.getRight(),
+                    view.getBottom(), view, view.getLayoutParams());
+        }
 
         if (setExtendedInfo) {
             MarginLayoutParams marginParams = null;
@@ -1427,39 +1498,92 @@
                     marginParams != null ? marginParams.bottomMargin : 0);
         }
 
-        if (view instanceof ViewGroup) {
-            ViewGroup group = ((ViewGroup) view);
-            result.setChildren(visitAllChildren(group, 0 /*offset*/, setExtendedInfo));
-        }
-
         return result;
     }
 
     /**
-     * Visits all the children of a given ViewGroup generate a list of {@link ViewInfo}
-     * containing the bounds of all the views.
-     * @param view the root View
-     * @param offset an offset for the view bounds.
-     * @param setExtendedInfo whether to set the extended view info in the {@link ViewInfo} object.
+     * The cookie for menu items are stored in menu item and not in the map from View stored in
+     * BridgeContext.
      */
-    private List<ViewInfo> visitAllChildren(ViewGroup viewGroup, int offset,
-            boolean setExtendedInfo) {
-        if (viewGroup == null) {
-            return null;
+    private Object getViewKey(View view) {
+        BridgeContext context = getContext();
+        if (!(view instanceof MenuView.ItemView)) {
+            return context.getViewKey(view);
+        }
+        MenuItemImpl menuItem;
+        if (view instanceof ActionMenuItemView) {
+            menuItem = ((ActionMenuItemView) view).getItemData();
+        } else if (view instanceof ListMenuItemView) {
+            menuItem = ((ListMenuItemView) view).getItemData();
+        } else if (view instanceof IconMenuItemView) {
+            menuItem = ((IconMenuItemView) view).getItemData();
+        } else {
+            menuItem = null;
+        }
+        if (menuItem instanceof BridgeMenuItemImpl) {
+            return ((BridgeMenuItemImpl) menuItem).getViewCookie();
         }
 
-        List<ViewInfo> children = new ArrayList<ViewInfo>();
-        for (int i = 0; i < viewGroup.getChildCount(); i++) {
-            children.add(visit(viewGroup.getChildAt(i), offset, setExtendedInfo));
-        }
-        return children;
+        return null;
     }
 
-
     private void invalidateRenderingSize() {
         mMeasuredScreenWidth = mMeasuredScreenHeight = -1;
     }
 
+    /**
+     * Creates the status bar with wifi and battery icons.
+     */
+    private StatusBar createStatusBar(BridgeContext context, Density density, int direction,
+            boolean isRtlSupported) throws XmlPullParserException {
+        StatusBar statusBar = new StatusBar(context, density,
+                direction, isRtlSupported);
+        statusBar.setLayoutParams(
+                new LinearLayout.LayoutParams(
+                        LayoutParams.MATCH_PARENT, mStatusBarSize));
+        return statusBar;
+    }
+
+    /**
+     * Creates the navigation bar with back, home and recent buttons.
+     *
+     * @param isRtl true if the current locale is right-to-left
+     * @param isRtlSupported true is the project manifest declares that the application
+     *        is RTL aware.
+     */
+    private NavigationBar createNavigationBar(BridgeContext context, Density density,
+            boolean isRtl, boolean isRtlSupported) throws XmlPullParserException {
+        NavigationBar navigationBar = new NavigationBar(context,
+                density, mNavigationBarOrientation, isRtl,
+                isRtlSupported);
+        if (mNavigationBarOrientation == LinearLayout.VERTICAL) {
+            navigationBar.setLayoutParams(new LinearLayout.LayoutParams(mNavigationBarSize,
+                    LayoutParams.MATCH_PARENT));
+        } else {
+            navigationBar.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT,
+                    mNavigationBarSize));
+        }
+        return navigationBar;
+    }
+
+    private TitleBar createTitleBar(BridgeContext context, Density density, String title)
+            throws XmlPullParserException {
+        TitleBar titleBar = new TitleBar(context, density, title);
+        titleBar.setLayoutParams(
+                new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, mTitleBarSize));
+        return titleBar;
+    }
+
+    /**
+     * Creates the action bar. Also queries the project callback for missing information.
+     */
+    private ActionBarLayout createActionBar(BridgeContext context, SessionParams params) {
+        ActionBarLayout actionBar = new ActionBarLayout(context, params);
+        actionBar.setLayoutParams(new LinearLayout.LayoutParams(
+                LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
+        return actionBar;
+    }
+
     public BufferedImage getImage() {
         return mImage;
     }
@@ -1472,6 +1596,10 @@
         return mViewInfoList;
     }
 
+    public List<ViewInfo> getSystemViewInfos() {
+        return mSystemViewInfoList;
+    }
+
     public Map<String, String> getDefaultProperties(Object viewObject) {
         return getContext().getDefaultPropMap(viewObject);
     }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java
index 6dcb693..adb0937 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java
@@ -165,6 +165,9 @@
      * @param context the current context
      */
     public static Drawable getDrawable(ResourceValue value, BridgeContext context) {
+        if (value == null) {
+            return null;
+        }
         String stringValue = value.getValue();
         if (RenderResources.REFERENCE_NULL.equals(stringValue)) {
             return null;
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/SystemViewInfo.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/SystemViewInfo.java
new file mode 100644
index 0000000..5c267df
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/SystemViewInfo.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.layoutlib.bridge.impl;
+
+import com.android.ide.common.rendering.api.ViewInfo;
+
+public class SystemViewInfo extends ViewInfo {
+
+    public SystemViewInfo(String name, Object cookie, int left, int top,
+            int right, int bottom) {
+        super(name, cookie, left, top, right, bottom);
+    }
+
+    public SystemViewInfo(String name, Object cookie, int left, int top,
+            int right, int bottom, Object viewObject, Object layoutParamsObject) {
+        super(name, cookie, left, top, right, bottom, viewObject,
+                layoutParamsObject);
+    }
+
+    @Override
+    public boolean isSystemView() {
+        return true;
+    }
+}
diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/TestDelegates.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/TestDelegates.java
index d3218db..7c0bc84 100644
--- a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/TestDelegates.java
+++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/TestDelegates.java
@@ -129,6 +129,15 @@
                                 originalClass.getName()),
                         delegateMethod.getAnnotation(LayoutlibDelegate.class));
 
+                // check the return type of the methods match.
+                assertTrue(
+                        String.format("Delegate method %1$s.%2$s does not match the corresponding " +
+                                "framework method which returns %3$s",
+                                delegateClass.getName(),
+                                getMethodName(delegateMethod),
+                                originalMethod.getReturnType().getName()),
+                        delegateMethod.getReturnType() == originalMethod.getReturnType());
+
                 // check that the method is static
                 assertTrue(
                         String.format(
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmAnalyzer.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmAnalyzer.java
index 9a31705..3e75c9e 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmAnalyzer.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmAnalyzer.java
@@ -632,8 +632,8 @@
             // field instruction
             @Override
             public void visitFieldInsn(int opcode, String owner, String name, String desc) {
-                // name is the field's name.
-                considerName(name);
+                // owner is the class that declares the field.
+                considerName(owner);
                 // desc is the field's descriptor (see Type).
                 considerDesc(desc);
             }
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
index 79aa642..911df7d 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
@@ -125,6 +125,9 @@
         "android.app.Fragment#instantiate", //(Landroid/content/Context;Ljava/lang/String;Landroid/os/Bundle;)Landroid/app/Fragment;",
         "android.content.res.Resources$Theme#obtainStyledAttributes",
         "android.content.res.Resources$Theme#resolveAttribute",
+        "android.content.res.AssetManager#newTheme",
+        "android.content.res.AssetManager#deleteTheme",
+        "android.content.res.AssetManager#applyThemeStyle",
         "android.content.res.TypedArray#getValueAt",
         "android.graphics.BitmapFactory#finishDecode",
         "android.os.Handler#sendMessageAtTime",
@@ -133,12 +136,15 @@
         "android.text.format.DateFormat#is24HourFormat",
         "android.view.Choreographer#getRefreshRate",
         "android.view.Display#updateDisplayInfoLocked",
+        "android.view.Display#getWindowManager",
         "android.view.LayoutInflater#rInflate",
         "android.view.LayoutInflater#parseInclude",
         "android.view.View#isInEditMode",
         "android.view.ViewRootImpl#isInTouchMode",
         "android.view.WindowManagerGlobal#getWindowManagerService",
         "android.view.inputmethod.InputMethodManager#getInstance",
+        "android.view.MenuInflater#registerMenu",
+        "com.android.internal.view.menu.MenuBuilder#createNewMenuItem",
         "com.android.internal.util.XmlUtils#convertValueToInt",
         "com.android.internal.textservice.ITextServicesManager$Stub#asInterface",
     };
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DependencyFinder.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DependencyFinder.java
index c988c70..2016c0e 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DependencyFinder.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DependencyFinder.java
@@ -527,7 +527,8 @@
             // field instruction
             @Override
             public void visitFieldInsn(int opcode, String owner, String name, String desc) {
-                // name is the field's name.
+                // owner is the class that declares the field.
+                considerName(owner);
                 // desc is the field's descriptor (see Type).
                 considerDesc(desc);
             }
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java
index a79fba1..2e952fc 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java
@@ -114,6 +114,9 @@
                         "android.os.*",  // for android.os.Handler
                         "android.database.ContentObserver", // for Digital clock
                         "com.android.i18n.phonenumbers.*",  // for TextView with autolink attribute
+                        "android.app.DatePickerDialog",     // b.android.com/28318
+                        "android.app.TimePickerDialog",     // b.android.com/61515
+                        "com.android.internal.view.menu.ActionMenu",
                     },
                     excludeClasses,
                     new String[] {
diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmAnalyzerTest.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmAnalyzerTest.java
index 7ec0d38..78e2c48 100644
--- a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmAnalyzerTest.java
+++ b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmAnalyzerTest.java
@@ -83,6 +83,7 @@
                 "mock_android.dummy.InnerTest$MyStaticInnerClass",
                 "mock_android.dummy.InnerTest$NotStaticInner1",
                 "mock_android.dummy.InnerTest$NotStaticInner2",
+                "mock_android.util.EmptyArray",
                 "mock_android.view.View",
                 "mock_android.view.ViewGroup",
                 "mock_android.view.ViewGroup$LayoutParams",
@@ -217,15 +218,16 @@
         TreeMap<String, ClassReader> in_deps = new TreeMap<String, ClassReader>();
         TreeMap<String, ClassReader> out_deps = new TreeMap<String, ClassReader>();
 
-        ClassReader cr = mAa.findClass("mock_android.widget.TableLayout", zipClasses, keep);
+        ClassReader cr = mAa.findClass("mock_android.widget.LinearLayout", zipClasses, keep);
         DependencyVisitor visitor = mAa.getVisitor(zipClasses, keep, new_keep, in_deps, out_deps);
 
         // get first level dependencies
         cr.accept(visitor, 0 /* flags */);
 
         assertArrayEquals(new String[] {
+                "mock_android.util.EmptyArray",
                 "mock_android.view.ViewGroup",
-                "mock_android.widget.TableLayout$LayoutParams",
+                "mock_android.widget.LinearLayout$LayoutParams",
             },
             out_deps.keySet().toArray());
 
@@ -255,7 +257,7 @@
 
         assertArrayEquals(new String[] { }, out_deps.keySet().toArray());
         assertArrayEquals(new String[] {
-                "mock_android.widget.TableLayout",
+                "mock_android.widget.LinearLayout",
         }, keep.keySet().toArray());
     }
 }
diff --git a/tools/layoutlib/create/tests/data/mock_android.jar b/tools/layoutlib/create/tests/data/mock_android.jar
index 8dd0481..c6ca3c4 100644
--- a/tools/layoutlib/create/tests/data/mock_android.jar
+++ b/tools/layoutlib/create/tests/data/mock_android.jar
Binary files differ
diff --git a/tools/layoutlib/create/tests/mock_data/mock_android/util/EmptyArray.java b/tools/layoutlib/create/tests/mock_data/mock_android/util/EmptyArray.java
new file mode 100644
index 0000000..aaeebf6
--- /dev/null
+++ b/tools/layoutlib/create/tests/mock_data/mock_android/util/EmptyArray.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Eclipse Public License, Version 1.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.eclipse.org/org/documents/epl-v10.php
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package mock_android.util;
+
+import java.lang.JavaClass;
+
+public class EmptyArray {
+
+        public static final Object[] OBJECT = new Object[0];
+}
diff --git a/tools/layoutlib/create/tests/mock_data/mock_android/widget/LinearLayout.java b/tools/layoutlib/create/tests/mock_data/mock_android/widget/LinearLayout.java
index 3870a63..af56c4b 100644
--- a/tools/layoutlib/create/tests/mock_data/mock_android/widget/LinearLayout.java
+++ b/tools/layoutlib/create/tests/mock_data/mock_android/widget/LinearLayout.java
@@ -16,11 +16,13 @@
 
 package mock_android.widget;
 
+import mock_android.util.EmptyArray;
 import mock_android.view.ViewGroup;
 
 public class LinearLayout extends ViewGroup {
 
-    public class LayoutParams extends mock_android.view.ViewGroup.LayoutParams {
+    Object[] mObjects = EmptyArray.OBJECT;
+    public class LayoutParams extends MarginLayoutParams {
 
     }
 
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index 0fffd373..1dc7da8 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -233,8 +233,6 @@
     private DhcpStateMachine mDhcpStateMachine;
     private boolean mDhcpActive = false;
 
-    // Delay in switching to null country code (non-null has no delay)
-    private final int COUNTRY_CODE_DELAY_MS = 15000;
     private final AtomicInteger mCountryCodeSequence = new AtomicInteger();
 
     private class InterfaceObserver extends BaseNetworkObserver {
@@ -1539,15 +1537,13 @@
      * @param persist {@code true} if the setting should be remembered.
      */
     public void setCountryCode(String countryCode, boolean persist) {
-        // If it's a country code, apply immediately,
-        // If it's empty, delay it in case it's a momentary dropout
+        // If it's a good country code, apply after the current
+        // wifi connection is terminated; ignore resetting of code
+        // for now (it is unclear what the chipset should do when
+        // country code is reset)
         int countryCodeSequence = mCountryCodeSequence.incrementAndGet();
         if (TextUtils.isEmpty(countryCode)) {
-            String defaultCountryCode = mContext.getResources().getString(
-                    R.string.config_wifi_unknown_country_code);
-
-            sendMessageDelayed(CMD_SET_COUNTRY_CODE, countryCodeSequence, persist ? 1 : 0,
-                    defaultCountryCode, COUNTRY_CODE_DELAY_MS);
+            log("Ignoring resetting of country code");
         } else {
             sendMessage(CMD_SET_COUNTRY_CODE, countryCodeSequence, persist ? 1 : 0, countryCode);
         }
@@ -1662,6 +1658,8 @@
         pw.println("mSuspendOptNeedsDisabled " + mSuspendOptNeedsDisabled);
         pw.println("Supplicant status " + mWifiNative.status());
         pw.println("mEnableBackgroundScan " + mEnableBackgroundScan);
+        pw.println("mLastSetCountryCode " + mLastSetCountryCode);
+        pw.println("mPersistedCountryCode " + mPersistedCountryCode);
         pw.println();
         mWifiConfigStore.dump(fd, pw, args);
     }
@@ -3680,6 +3678,9 @@
                         deferMessage(message);
                     }
                     break;
+                case CMD_SET_COUNTRY_CODE:
+                    deferMessage(message);
+                    break;
                 case CMD_START_SCAN:
                     /* Do not attempt to connect when we are already connected */
                     noteScanStart(message.arg1, (WorkSource) message.obj);