am c8a045d4: am 41f40581: Merge "Fix x86 build in app_process."

* commit 'c8a045d451522adab5226b0063f3a15d34542bf7':
  Fix x86 build in app_process.
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..408b3f8 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
@@ -311,6 +313,7 @@
     field public static final int backgroundSplit = 16843659; // 0x101038b
     field public static final int backgroundStacked = 16843658; // 0x101038a
     field public static final int backupAgent = 16843391; // 0x101027f
+    field public static final int banner = 16843762; // 0x10103f2
     field public static final int baseline = 16843548; // 0x101031c
     field public static final int baselineAlignBottom = 16843042; // 0x1010122
     field public static final int baselineAligned = 16843046; // 0x1010126
@@ -620,6 +623,7 @@
     field public static final int isAsciiCapable = 16843753; // 0x10103e9
     field public static final int isAuxiliary = 16843647; // 0x101037f
     field public static final int isDefault = 16843297; // 0x1010221
+    field public static final int isGame = 16843764; // 0x10103f4
     field public static final int isIndicator = 16843079; // 0x1010147
     field public static final int isModifier = 16843334; // 0x1010246
     field public static final int isRepeatable = 16843336; // 0x1010248
@@ -1221,6 +1225,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
@@ -2850,6 +2855,7 @@
     method public void onUserInteraction();
     method protected void onUserLeaveHint();
     method public void onWindowAttributesChanged(android.view.WindowManager.LayoutParams);
+    method public void onWindowDismissed();
     method public void onWindowFocusChanged(boolean);
     method public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback);
     method public void openContextMenu(android.view.View);
@@ -3366,6 +3372,7 @@
     method public boolean onTouchEvent(android.view.MotionEvent);
     method public boolean onTrackballEvent(android.view.MotionEvent);
     method public void onWindowAttributesChanged(android.view.WindowManager.LayoutParams);
+    method public void onWindowDismissed();
     method public void onWindowFocusChanged(boolean);
     method public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback);
     method public void openContextMenu(android.view.View);
@@ -3915,6 +3922,20 @@
     method public int describeContents();
     method public deprecated void setLatestEventInfo(android.content.Context, java.lang.CharSequence, java.lang.CharSequence, android.app.PendingIntent);
     method public void writeToParcel(android.os.Parcel, int);
+    field public static final java.lang.String CATEGORY_ALARM = "alarm";
+    field public static final java.lang.String CATEGORY_CALL = "call";
+    field public static final java.lang.String CATEGORY_EMAIL = "email";
+    field public static final java.lang.String CATEGORY_ERROR = "err";
+    field public static final java.lang.String CATEGORY_EVENT = "event";
+    field public static final java.lang.String CATEGORY_MESSAGE = "msg";
+    field public static final java.lang.String CATEGORY_PROGRESS = "progress";
+    field public static final java.lang.String CATEGORY_PROMO = "promo";
+    field public static final java.lang.String CATEGORY_RECOMMENDATION = "recommendation";
+    field public static final java.lang.String CATEGORY_SERVICE = "service";
+    field public static final java.lang.String CATEGORY_SOCIAL = "social";
+    field public static final java.lang.String CATEGORY_STATUS = "status";
+    field public static final java.lang.String CATEGORY_SYSTEM = "sys";
+    field public static final java.lang.String CATEGORY_TRANSPORT = "transport";
     field public static final android.os.Parcelable.Creator CREATOR;
     field public static final int DEFAULT_ALL = -1; // 0xffffffff
     field public static final int DEFAULT_LIGHTS = 4; // 0x4
@@ -3941,6 +3962,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
@@ -3954,6 +3976,7 @@
     field public android.app.Notification.Action[] actions;
     field public int audioStreamType;
     field public android.widget.RemoteViews bigContentView;
+    field public java.lang.String category;
     field public android.app.PendingIntent contentIntent;
     field public android.widget.RemoteViews contentView;
     field public int defaults;
@@ -4007,9 +4030,12 @@
   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 setCategory(java.lang.String);
     method public android.app.Notification.Builder setContent(android.widget.RemoteViews);
     method public android.app.Notification.Builder setContentInfo(java.lang.CharSequence);
     method public android.app.Notification.Builder setContentIntent(android.app.PendingIntent);
@@ -4021,6 +4047,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);
@@ -5987,6 +6014,7 @@
     field public static final java.lang.String DISPLAY_SERVICE = "display";
     field public static final java.lang.String DOWNLOAD_SERVICE = "download";
     field public static final java.lang.String DROPBOX_SERVICE = "dropbox";
+    field public static final java.lang.String HDMI_CEC_SERVICE = "hdmi_cec";
     field public static final java.lang.String INPUT_METHOD_SERVICE = "input_method";
     field public static final java.lang.String INPUT_SERVICE = "input";
     field public static final java.lang.String KEYGUARD_SERVICE = "keyguard";
@@ -6442,6 +6470,7 @@
     field public static final java.lang.String CATEGORY_HOME = "android.intent.category.HOME";
     field public static final java.lang.String CATEGORY_INFO = "android.intent.category.INFO";
     field public static final java.lang.String CATEGORY_LAUNCHER = "android.intent.category.LAUNCHER";
+    field public static final java.lang.String CATEGORY_LEANBACK_LAUNCHER = "android.intent.category.LEANBACK_LAUNCHER";
     field public static final java.lang.String CATEGORY_LE_DESK_DOCK = "android.intent.category.LE_DESK_DOCK";
     field public static final java.lang.String CATEGORY_MONKEY = "android.intent.category.MONKEY";
     field public static final java.lang.String CATEGORY_OPENABLE = "android.intent.category.OPENABLE";
@@ -7024,6 +7053,7 @@
     field public static final int FLAG_HAS_CODE = 4; // 0x4
     field public static final int FLAG_INSTALLED = 8388608; // 0x800000
     field public static final int FLAG_IS_DATA_ONLY = 16777216; // 0x1000000
+    field public static final int FLAG_IS_GAME = 33554432; // 0x2000000
     field public static final int FLAG_KILL_AFTER_RESTORE = 65536; // 0x10000
     field public static final int FLAG_LARGE_HEAP = 1048576; // 0x100000
     field public static final int FLAG_PERSISTENT = 8; // 0x8
@@ -7072,6 +7102,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 +7206,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 +7240,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;
@@ -7228,6 +7265,7 @@
     method public abstract java.lang.String getInstallerPackageName(java.lang.String);
     method public abstract android.content.pm.InstrumentationInfo getInstrumentationInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract android.content.Intent getLaunchIntentForPackage(java.lang.String);
+    method public abstract android.content.Intent getLeanbackLaunchIntentForPackage(java.lang.String);
     method public abstract java.lang.String getNameForUid(int);
     method public android.content.pm.PackageInfo getPackageArchiveInfo(java.lang.String, int);
     method public abstract int[] getPackageGids(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -7277,6 +7315,7 @@
     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";
@@ -7291,6 +7330,7 @@
     field public static final java.lang.String FEATURE_FAKETOUCH_MULTITOUCH_JAZZHAND = "android.hardware.faketouch.multitouch.jazzhand";
     field public static final java.lang.String FEATURE_HOME_SCREEN = "android.software.home_screen";
     field public static final java.lang.String FEATURE_INPUT_METHODS = "android.software.input_methods";
+    field public static final java.lang.String FEATURE_LEANBACK = "android.software.leanback";
     field public static final java.lang.String FEATURE_LIVE_WALLPAPER = "android.software.live_wallpaper";
     field public static final java.lang.String FEATURE_LOCATION = "android.hardware.location";
     field public static final java.lang.String FEATURE_LOCATION_GPS = "android.hardware.location.gps";
@@ -7298,6 +7338,7 @@
     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";
@@ -7313,13 +7354,14 @@
     field public static final java.lang.String FEATURE_TELEPHONY = "android.hardware.telephony";
     field public static final java.lang.String FEATURE_TELEPHONY_CDMA = "android.hardware.telephony.cdma";
     field public static final java.lang.String FEATURE_TELEPHONY_GSM = "android.hardware.telephony.gsm";
-    field public static final java.lang.String FEATURE_TELEVISION = "android.hardware.type.television";
+    field public static final deprecated java.lang.String FEATURE_TELEVISION = "android.hardware.type.television";
     field public static final java.lang.String FEATURE_TOUCHSCREEN = "android.hardware.touchscreen";
     field public static final java.lang.String FEATURE_TOUCHSCREEN_MULTITOUCH = "android.hardware.touchscreen.multitouch";
     field public static final java.lang.String FEATURE_TOUCHSCREEN_MULTITOUCH_DISTINCT = "android.hardware.touchscreen.multitouch.distinct";
     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 +7684,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;
@@ -10715,10 +10758,33 @@
     method public int getMinDelay();
     method public java.lang.String getName();
     method public float getPower();
+    method public java.lang.String getRequiredPermission();
     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 +10793,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 +10937,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 +10951,142 @@
 
   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);
+  }
+
+}
+
+package android.hardware.hdmi {
+
+  public final class HdmiCec {
+    method public static java.lang.String getDefaultDeviceName(int);
+    method public static int getTypeFromAddress(int);
+    method public static boolean isValidAddress(int);
+    method public static boolean isValidType(int);
+    field public static final int ADDR_AUDIO_SYSTEM = 5; // 0x5
+    field public static final int ADDR_BROADCAST = 15; // 0xf
+    field public static final int ADDR_FREE_USE = 14; // 0xe
+    field public static final int ADDR_INVALID = -1; // 0xffffffff
+    field public static final int ADDR_PLAYBACK_1 = 4; // 0x4
+    field public static final int ADDR_PLAYBACK_2 = 8; // 0x8
+    field public static final int ADDR_PLAYBACK_3 = 11; // 0xb
+    field public static final int ADDR_RECORDER_1 = 1; // 0x1
+    field public static final int ADDR_RECORDER_2 = 2; // 0x2
+    field public static final int ADDR_RECORDER_3 = 9; // 0x9
+    field public static final int ADDR_RESERVED_1 = 12; // 0xc
+    field public static final int ADDR_RESERVED_2 = 13; // 0xd
+    field public static final int ADDR_TUNER_1 = 3; // 0x3
+    field public static final int ADDR_TUNER_2 = 6; // 0x6
+    field public static final int ADDR_TUNER_3 = 7; // 0x7
+    field public static final int ADDR_TUNER_4 = 10; // 0xa
+    field public static final int ADDR_TV = 0; // 0x0
+    field public static final int ADDR_UNREGISTERED = 15; // 0xf
+    field public static final int DEVICE_AUDIO_SYSTEM = 5; // 0x5
+    field public static final int DEVICE_INACTIVE = -1; // 0xffffffff
+    field public static final int DEVICE_PLAYBACK = 4; // 0x4
+    field public static final int DEVICE_RECORDER = 1; // 0x1
+    field public static final int DEVICE_RESERVED = 2; // 0x2
+    field public static final int DEVICE_TUNER = 3; // 0x3
+    field public static final int DEVICE_TV = 0; // 0x0
+    field public static final int MESSAGE_ABORT = 255; // 0xff
+    field public static final int MESSAGE_ACTIVE_SOURCE = 130; // 0x82
+    field public static final int MESSAGE_CEC_VERSION = 158; // 0x9e
+    field public static final int MESSAGE_CLEAR_ANALOG_TIMER = 51; // 0x33
+    field public static final int MESSAGE_CLEAR_DIGITAL_TIMER = 153; // 0x99
+    field public static final int MESSAGE_CLEAR_EXTERNAL_TIMER = 161; // 0xa1
+    field public static final int MESSAGE_DECK_CONTROL = 66; // 0x42
+    field public static final int MESSAGE_DECK_STATUS = 27; // 0x1b
+    field public static final int MESSAGE_DEVICE_VENDOR_ID = 135; // 0x87
+    field public static final int MESSAGE_FEATURE_ABORT = 0; // 0x0
+    field public static final int MESSAGE_GET_CEC_VERSION = 159; // 0x9f
+    field public static final int MESSAGE_GET_MENU_LANGUAGE = 145; // 0x91
+    field public static final int MESSAGE_GET_OSD_NAME = 70; // 0x46
+    field public static final int MESSAGE_GIVE_AUDIO_STATUS = 113; // 0x71
+    field public static final int MESSAGE_GIVE_DECK_STATUS = 26; // 0x1a
+    field public static final int MESSAGE_GIVE_DEVICE_POWER_STATUS = 143; // 0x8f
+    field public static final int MESSAGE_GIVE_DEVICE_VENDOR_ID = 140; // 0x8c
+    field public static final int MESSAGE_GIVE_PHYSICAL_ADDRESS = 131; // 0x83
+    field public static final int MESSAGE_GIVE_SYSTEM_AUDIO_MODE_STATUS = 125; // 0x7d
+    field public static final int MESSAGE_GIVE_TUNER_DEVICE_STATUS = 8; // 0x8
+    field public static final int MESSAGE_IMAGE_VIEW_ON = 4; // 0x4
+    field public static final int MESSAGE_INACTIVE_SOURCE = 157; // 0x9d
+    field public static final int MESSAGE_MENU_REQUEST = 141; // 0x8d
+    field public static final int MESSAGE_MENU_STATUS = 142; // 0x8e
+    field public static final int MESSAGE_PLAY = 65; // 0x41
+    field public static final int MESSAGE_RECORD_OFF = 11; // 0xb
+    field public static final int MESSAGE_RECORD_ON = 9; // 0x9
+    field public static final int MESSAGE_RECORD_STATUS = 10; // 0xa
+    field public static final int MESSAGE_RECORD_TV_SCREEN = 15; // 0xf
+    field public static final int MESSAGE_REPORT_AUDIO_STATUS = 122; // 0x7a
+    field public static final int MESSAGE_REPORT_PHYSICAL_ADDRESS = 132; // 0x84
+    field public static final int MESSAGE_REPORT_POWER_STATUS = 144; // 0x90
+    field public static final int MESSAGE_REQUEST_ACTIVE_SOURCE = 133; // 0x85
+    field public static final int MESSAGE_ROUTING_CHANGE = 128; // 0x80
+    field public static final int MESSAGE_ROUTING_INFORMATION = 129; // 0x81
+    field public static final int MESSAGE_SELECT_ANALOG_SERVICE = 146; // 0x92
+    field public static final int MESSAGE_SELECT_DIGITAL_SERVICE = 147; // 0x93
+    field public static final int MESSAGE_SET_ANALOG_TIMER = 52; // 0x34
+    field public static final int MESSAGE_SET_AUDIO_RATE = 154; // 0x9a
+    field public static final int MESSAGE_SET_DIGITAL_TIMER = 151; // 0x97
+    field public static final int MESSAGE_SET_EXTERNAL_TIMER = 162; // 0xa2
+    field public static final int MESSAGE_SET_MENU_LANGUAGE = 50; // 0x32
+    field public static final int MESSAGE_SET_OSD_NAME = 71; // 0x47
+    field public static final int MESSAGE_SET_OSD_STRING = 100; // 0x64
+    field public static final int MESSAGE_SET_STREAM_PATH = 134; // 0x86
+    field public static final int MESSAGE_SET_SYSTEM_AUDIO_MODE = 114; // 0x72
+    field public static final int MESSAGE_SET_TIMER_PROGRAM_TITLE = 103; // 0x67
+    field public static final int MESSAGE_STANDBY = 54; // 0x36
+    field public static final int MESSAGE_SYSTEM_AUDIO_MODE_REQUEST = 112; // 0x70
+    field public static final int MESSAGE_SYSTEM_AUDIO_MODE_STATUS = 126; // 0x7e
+    field public static final int MESSAGE_TEXT_VIEW_ON = 13; // 0xd
+    field public static final int MESSAGE_TIMER_CLEARED_STATUS = 67; // 0x43
+    field public static final int MESSAGE_TIMER_STATUS = 53; // 0x35
+    field public static final int MESSAGE_TUNER_DEVICE_STATUS = 7; // 0x7
+    field public static final int MESSAGE_TUNER_STEP_DECREMENT = 6; // 0x6
+    field public static final int MESSAGE_TUNER_STEP_INCREMENT = 5; // 0x5
+    field public static final int MESSAGE_USER_CONTROL_PRESSED = 68; // 0x44
+    field public static final int MESSAGE_USER_CONTROL_RELEASED = 69; // 0x45
+    field public static final int MESSAGE_VENDOR_COMMAND = 137; // 0x89
+    field public static final int MESSAGE_VENDOR_COMMAND_WITH_ID = 160; // 0xa0
+    field public static final int MESSAGE_VENDOR_REMOTE_BUTTON_DOWN = 138; // 0x8a
+    field public static final int MESSAGE_VENDOR_REMOTE_BUTTON_UP = 139; // 0x8b
+    field public static final int POWER_STATUS_ON = 0; // 0x0
+    field public static final int POWER_STATUS_STANDBY = 1; // 0x1
+    field public static final int POWER_STATUS_UNKNOWN = -1; // 0xffffffff
+    field public static final int POWER_TRANSIENT_TO_ON = 2; // 0x2
+    field public static final int POWER_TRANSIENT_TO_STANDBY = 3; // 0x3
+  }
+
+  public final class HdmiCecClient {
+    method public boolean isTvOn();
+    method public void sendActiveSource();
+    method public void sendGiveDevicePowerStatus(int);
+    method public void sendImageViewOn();
+    method public void sendInactiveSource();
+    method public void sendTextViewOn();
+  }
+
+  public static abstract class HdmiCecClient.Listener {
+    ctor public HdmiCecClient.Listener();
+    method public void onCableStatusChanged(boolean);
+    method public void onMessageReceived(android.hardware.hdmi.HdmiCecMessage);
+  }
+
+  public final class HdmiCecManager {
+    method public android.hardware.hdmi.HdmiCecClient getClient(int, android.hardware.hdmi.HdmiCecClient.Listener);
+  }
+
+  public final class HdmiCecMessage implements android.os.Parcelable {
+    ctor public HdmiCecMessage(int, int, int, byte[]);
+    method public int describeContents();
+    method public int getDestination();
+    method public int getOpcode();
+    method public byte[] getParams();
+    method public int getSource();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
   }
 
 }
@@ -14215,10 +14418,13 @@
   public final class NsdServiceInfo implements android.os.Parcelable {
     ctor public NsdServiceInfo();
     method public int describeContents();
+    method public java.util.Map<java.lang.String, byte[]> getAttributes();
     method public java.net.InetAddress getHost();
     method public int getPort();
     method public java.lang.String getServiceName();
     method public java.lang.String getServiceType();
+    method public void removeAttribute(java.lang.String);
+    method public void setAttribute(java.lang.String, java.lang.String);
     method public void setHost(java.net.InetAddress);
     method public void setPort(int);
     method public void setServiceName(java.lang.String);
@@ -17464,6 +17670,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 = 10000; // 0x2710
   }
 
   public final class Bundle implements java.lang.Cloneable android.os.Parcelable {
@@ -18148,7 +18355,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 +22002,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 +22693,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);
@@ -22698,6 +22915,7 @@
     method public boolean onPreparePanel(int, android.view.View, android.view.Menu);
     method public boolean onSearchRequested();
     method public void onWindowAttributesChanged(android.view.WindowManager.LayoutParams);
+    method public void onWindowDismissed();
     method public void onWindowFocusChanged(boolean);
     method public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback);
     method public void setContentView(int);
@@ -22718,8 +22936,11 @@
     ctor public NotificationListenerService();
     method public final void cancelAllNotifications();
     method public final void cancelNotification(java.lang.String, java.lang.String, int);
+    method public final void cancelNotifications(java.lang.String[]);
     method public android.service.notification.StatusBarNotification[] getActiveNotifications();
+    method public android.service.notification.StatusBarNotification[] getActiveNotifications(java.lang.String[]);
     method public android.os.IBinder onBind(android.content.Intent);
+    method public void onListenerConnected(java.lang.String[]);
     method public abstract void onNotificationPosted(android.service.notification.StatusBarNotification);
     method public abstract void onNotificationRemoved(android.service.notification.StatusBarNotification);
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationListenerService";
@@ -22731,6 +22952,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 +24282,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;
@@ -24081,6 +24307,7 @@
     method public java.lang.String getInstallerPackageName(java.lang.String);
     method public android.content.pm.InstrumentationInfo getInstrumentationInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public android.content.Intent getLaunchIntentForPackage(java.lang.String);
+    method public android.content.Intent getLeanbackLaunchIntentForPackage(java.lang.String);
     method public java.lang.String getNameForUid(int);
     method public int[] getPackageGids(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public android.content.pm.PackageInfo getPackageInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -26178,7 +26405,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 +26589,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 +26597,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 {
@@ -26512,6 +26743,7 @@
     method public android.os.Vibrator getVibrator();
     method public boolean[] hasKeys(int...);
     method public boolean isVirtual();
+    method public boolean supportsSource(int);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator CREATOR;
     field public static final int KEYBOARD_TYPE_ALPHABETIC = 2; // 0x2
@@ -26664,8 +26896,10 @@
     method public final boolean hasModifiers(int);
     method public final boolean hasNoModifiers();
     method public final boolean isAltPressed();
+    method public final boolean isCancelKey();
     method public final boolean isCanceled();
     method public final boolean isCapsLockOn();
+    method public final boolean isConfirmKey();
     method public final boolean isCtrlPressed();
     method public final boolean isFunctionPressed();
     method public static final boolean isGamepadButton(int);
@@ -26701,7 +26935,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 +27130,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 +27152,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 +27764,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 +27796,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 +27978,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 +28045,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 +28110,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 +28329,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);
@@ -28646,6 +28890,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
@@ -28677,6 +28922,7 @@
     method public abstract boolean onPreparePanel(int, android.view.View, android.view.Menu);
     method public abstract boolean onSearchRequested();
     method public abstract void onWindowAttributesChanged(android.view.WindowManager.LayoutParams);
+    method public abstract void onWindowDismissed();
     method public abstract void onWindowFocusChanged(boolean);
     method public abstract android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback);
   }
@@ -28696,6 +28942,28 @@
     method public abstract void onFocusLost(android.view.WindowId);
   }
 
+  public class WindowInsets {
+    ctor public WindowInsets(android.view.WindowInsets);
+    method public android.view.WindowInsets cloneWithSystemWindowInsets(int, int, int, int);
+    method public android.view.WindowInsets cloneWithSystemWindowInsetsConsumed();
+    method public android.view.WindowInsets cloneWithSystemWindowInsetsConsumed(boolean, boolean, boolean, boolean);
+    method public android.view.WindowInsets cloneWithWindowDecorInsets(int, int, int, int);
+    method public android.view.WindowInsets cloneWithWindowDecorInsetsConsumed();
+    method public android.view.WindowInsets cloneWithWindowDecorInsetsConsumed(boolean, boolean, boolean, boolean);
+    method public int getSystemWindowInsetBottom();
+    method public int getSystemWindowInsetLeft();
+    method public int getSystemWindowInsetRight();
+    method public int getSystemWindowInsetTop();
+    method public int getWindowDecorInsetBottom();
+    method public int getWindowDecorInsetLeft();
+    method public int getWindowDecorInsetRight();
+    method public int getWindowDecorInsetTop();
+    method public boolean hasInsets();
+    method public boolean hasSystemWindowInsets();
+    method public boolean hasWindowDecorInsets();
+    method public boolean isRound();
+  }
+
   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 +29029,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 +42991,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 +44435,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 +44457,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 +51199,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..63c9fec 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -2402,6 +2402,13 @@
         }
         return false;
     }
+
+    /**
+     * Called when the main window associated with the activity has been dismissed.
+     */
+    public void onWindowDismissed() {
+        finish();
+    }
     
     /**
      * Called to process key events.  You can override this to intercept all 
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..a810134
--- /dev/null
+++ b/core/java/android/app/ActivityView.java
@@ -0,0 +1,389 @@
+/*
+ * 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.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;
+
+    // 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);
+
+        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);
+    }
+
+    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..c5e6ac4 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -129,6 +129,24 @@
     }
 
     @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 {
         try {
@@ -729,6 +747,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..a8277b5 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -695,6 +695,10 @@
     
     public void onDetachedFromWindow() {
     }
+
+    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/Notification.java b/core/java/android/app/Notification.java
index cce6fc4..55e7470 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,82 @@
     public int priority;
 
     /**
-     * @hide
-     * Notification type: incoming call (voice or video) or similar synchronous communication request.
+     * Notification category: 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";
 
     /**
-     * @hide
-     * Notification type: incoming direct message (SMS, instant message, etc.).
+     * Notification category: incoming direct message (SMS, instant message, etc.).
      */
-    public static final String KIND_MESSAGE = "android.message";
+    public static final String CATEGORY_MESSAGE = "msg";
 
     /**
-     * @hide
-     * Notification type: asynchronous bulk message (email).
+     * Notification category: asynchronous bulk message (email).
      */
-    public static final String KIND_EMAIL = "android.email";
+    public static final String CATEGORY_EMAIL = "email";
 
     /**
-     * @hide
-     * Notification type: calendar event.
+     * Notification category: calendar event.
      */
-    public static final String KIND_EVENT = "android.event";
+    public static final String CATEGORY_EVENT = "event";
 
     /**
-     * @hide
-     * Notification type: promotion or advertisement.
+     * Notification category: promotion or advertisement.
      */
-    public static final String KIND_PROMO = "android.promo";
+    public static final String CATEGORY_PROMO = "promo";
 
     /**
-     * @hide
-     * If this notification matches of one or more special types (see the <code>KIND_*</code>
-     * constants), add them here, best match first.
+     * Notification category: alarm or timer.
      */
-    public String[] kind;
+    public static final String CATEGORY_ALARM = "alarm";
+
+    /**
+     * Notification category: progress of a long-running background operation.
+     */
+    public static final String CATEGORY_PROGRESS = "progress";
+
+    /**
+     * Notification category: social network or sharing update.
+     */
+    public static final String CATEGORY_SOCIAL = "social";
+
+    /**
+     * Notification category: error in background operation or authentication status.
+     */
+    public static final String CATEGORY_ERROR = "err";
+
+    /**
+     * Notification category: media transport control for playback.
+     */
+    public static final String CATEGORY_TRANSPORT = "transport";
+
+    /**
+     * Notification category: system or device status update.  Reserved for system use.
+     */
+    public static final String CATEGORY_SYSTEM = "sys";
+
+    /**
+     * Notification category: indication of running background service.
+     */
+    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.
+     */
+    public static final String CATEGORY_RECOMMENDATION = "recommendation";
+
+    /**
+     * Notification category: ongoing information about device or contextual status.
+     */
+    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.
+     */
+    public String category;
 
     /**
      * Additional semantic data to be carried around with this Notification.
@@ -561,6 +609,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 +805,7 @@
 
         priority = parcel.readInt();
 
-        kind = parcel.createStringArray(); // may set kind to null
+        category = parcel.readString();
 
         extras = parcel.readBundle(); // may be null
 
@@ -815,12 +870,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 +1007,7 @@
 
         parcel.writeInt(priority);
 
-        parcel.writeStringArray(kind); // ok for null
+        parcel.writeString(category);
 
         parcel.writeBundle(extras); // null ok
 
@@ -1077,16 +1127,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 +1206,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 +1573,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 +1608,41 @@
         }
 
         /**
-         * @hide
+         * Set the notification category.
          *
-         * Add a kind (category) to this notification. Optional.
-         *
-         * @see Notification#kind
+         * @see Notification#category
          */
-        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 +1651,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 +1905,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 +1920,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 +1958,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 +1981,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..5057cf4 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,16 @@
 
     /**
      * 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
+     */
+     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..95e27e2 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,12 @@
     @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.
+     */
+    @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 +3576,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 1a1610d..0172509 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -315,6 +315,12 @@
     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.
+     */
+    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.
      *
@@ -363,7 +369,7 @@
      * {@link #FLAG_SUPPORTS_LARGE_SCREENS}, {@link #FLAG_SUPPORTS_XLARGE_SCREENS},
      * {@link #FLAG_RESIZEABLE_FOR_SCREENS},
      * {@link #FLAG_SUPPORTS_SCREEN_DENSITIES}, {@link #FLAG_VM_SAFE_MODE},
-     * {@link #FLAG_INSTALLED}.
+     * {@link #FLAG_INSTALLED}, {@link #FLAG_IS_GAME}.
      */
     public int flags = 0;
 
@@ -483,7 +489,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..226f5a6 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -989,6 +989,7 @@
      * @hide
      * @deprecated
      */
+    @Deprecated
     @SdkConstant(SdkConstantType.FEATURE)
     public static final String FEATURE_NFC_HCE = "android.hardware.nfc.hce";
 
@@ -1244,6 +1245,26 @@
 
     /**
      * 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.
+     */
+    @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)
@@ -1263,11 +1284,36 @@
      * room television experience: displayed on a big screen, where the user
      * is sitting far away from it, and the dominant form of input will be
      * something like a DPAD, not through touch or mouse.
+     * @deprecated use {@link #FEATURE_LEANBACK} instead.
      */
+    @Deprecated
     @SdkConstant(SdkConstantType.FEATURE)
     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 +1476,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.
-     *
+     * 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 +2450,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 +2524,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 52564eb..66d4f50 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();
@@ -3701,6 +3733,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();
@@ -4125,6 +4162,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..4bea9ee 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,20 @@
         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.
+     */
+    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..8578a32
--- /dev/null
+++ b/core/java/android/hardware/hdmi/HdmiCec.java
@@ -0,0 +1,257 @@
+/*
+ * 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.
+ */
+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..cd86cd8
--- /dev/null
+++ b/core/java/android/hardware/hdmi/HdmiCecClient.java
@@ -0,0 +1,143 @@
+/*
+ * 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.
+ */
+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..10b058c
--- /dev/null
+++ b/core/java/android/hardware/hdmi/HdmiCecManager.java
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ */
+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..be94d97
--- /dev/null
+++ b/core/java/android/hardware/hdmi/HdmiCecMessage.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.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.
+ */
+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/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..6fdb0d0 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,134 @@
         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.
+     */
+    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 */
+    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}.
+     */
+    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 +235,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 +265,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/Build.java b/core/java/android/os/Build.java
index b2e0b29..fae2d52 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -474,6 +474,11 @@
          * </ul>
          */
         public static final int KITKAT = 19;
+
+        /**
+         * Android 4.5: KitKat for watches, snacks on the run.
+         */
+        public static final int KITKAT_WATCH = CUR_DEVELOPMENT; // STOPSHIP: update API level
     }
     
     /** The type of build, like "user" or "eng". */
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 5dc4058..b4ed68c 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -982,19 +982,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..2303d65 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
      */
@@ -289,6 +300,10 @@
     public void onDetachedFromWindow() {
     }
 
+    @Override
+    public void onWindowDismissed() {
+    }
+
     /** {@inheritDoc} */
     @Override
     public void onPanelClosed(int featureId, Menu menu) {
@@ -325,7 +340,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 +459,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 +484,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 +506,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 +524,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 +670,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 +695,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 +729,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 +771,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 +807,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 +818,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 +845,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 +867,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..8eaee29 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -83,6 +83,17 @@
      */
     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.
+     */
+    public void onListenerConnected(String[] notificationKeys) {
+        // optional
+    }
+
     private final INotificationManager getNotificationInterface() {
         if (mNoMan == null) {
             mNoMan = INotificationManager.Stub.asInterface(
@@ -112,6 +123,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 +143,23 @@
      * {@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)}
+     */
+    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 +167,25 @@
 
     /**
      * 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.
+     */
+    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 +200,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 +225,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..ae5f37e 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,19 @@
     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.
+     */
+    public boolean supportsSource(int source) {
+        return (mSources & source) == source;
+    }
+
     /**
      * Gets the keyboard type.
      * @return The keyboard type.
@@ -569,7 +597,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..7b389c0 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,32 @@
         }
     }
 
-    /** Whether key will, by default, trigger a click on the focused view.
-     * @hide
+    /**
+     * 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}.
      */
-    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}.
+     */
+    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..eb7f45e 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.cloneWithSystemWindowInsetsConsumed();
+            }
+        } else {
+            // We were called from within a direct call to fitSystemWindows.
+            if (fitSystemWindowsInt(insets.getSystemWindowInsets())) {
+                return insets.cloneWithSystemWindowInsetsConsumed();
+            }
+        }
+        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;
             }
@@ -16499,7 +16633,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 +16728,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 +16974,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 +18511,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 +18802,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 +18872,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 +18938,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/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 9414237..f346ee8 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++) {
@@ -5430,21 +5429,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..c450f3c 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;
@@ -385,6 +390,12 @@
          * @param mode The mode that was just finished.
          */
         public void onActionModeFinished(ActionMode mode);
+
+        /**
+         * 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) {
diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java
new file mode 100644
index 0000000..2160efe
--- /dev/null
+++ b/core/java/android/view/WindowInsets.java
@@ -0,0 +1,304 @@
+/*
+ * 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 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
+     */
+    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
+     */
+    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
+     */
+    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
+     */
+    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
+     */
+    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;
+    }
+
+    public WindowInsets cloneWithSystemWindowInsetsConsumed() {
+        final WindowInsets result = new WindowInsets(this);
+        result.mSystemWindowInsets = new Rect(0, 0, 0, 0);
+        return result;
+    }
+
+    public WindowInsets cloneWithSystemWindowInsetsConsumed(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;
+    }
+
+    public WindowInsets cloneWithSystemWindowInsets(int left, int top, int right, int bottom) {
+        final WindowInsets result = new WindowInsets(this);
+        result.mSystemWindowInsets = new Rect(left, top, right, bottom);
+        return result;
+    }
+
+    public WindowInsets cloneWithWindowDecorInsetsConsumed() {
+        final WindowInsets result = new WindowInsets(this);
+        result.mWindowDecorInsets.set(0, 0, 0, 0);
+        return result;
+    }
+
+    public WindowInsets cloneWithWindowDecorInsetsConsumed(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;
+    }
+
+    public WindowInsets cloneWithWindowDecorInsets(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..893db89 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().
@@ -749,12 +734,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 +748,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.
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/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/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..8728610 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;
@@ -113,6 +114,10 @@
     }
 
     final class MyHandler extends Handler {
+        public MyHandler(Looper looper) {
+            super(looper, null, true);
+        }
+
         @Override
         public void handleMessage(Message msg) {
             BatteryCallback cb = mCallback;
@@ -4487,9 +4492,9 @@
         }
     }
 
-    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++) {
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..467d42e
--- /dev/null
+++ b/core/java/com/android/internal/widget/SwipeDismissLayout.java
@@ -0,0 +1,308 @@
+/*
+ * 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 TRANSLATION_MIN_ALPHA = 0.5f;
+
+    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;
+
+    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() * 16;
+        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);
+                updateSwiping(ev);
+                updateDismiss(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;
+            mSwiping = deltaX > mSlop * 2 && Math.abs(deltaY) < mSlop * 2;
+        }
+    }
+
+    private void updateDismiss(MotionEvent ev) {
+        float deltaX = ev.getRawX() - mDownX;
+        if (!mDismissed) {
+            mVelocityTracker.addMovement(ev);
+            mVelocityTracker.computeCurrentVelocity(1000);
+
+            float velocityX = mVelocityTracker.getXVelocity();
+            float absVelocityX = Math.abs(velocityX);
+            float absVelocityY = Math.abs(mVelocityTracker.getYVelocity());
+
+            if (deltaX > getWidth() / 2) {
+                mDismissed = true;
+            } else if (absVelocityX >= mMinFlingVelocity
+                    && absVelocityX <= mMaxFlingVelocity
+                    && absVelocityY < absVelocityX / 2
+                    && velocityX > 0
+                    && deltaX > 0) {
+                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() / 2) {
+                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/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..a1c09214
--- /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..1dd4608
--- /dev/null
+++ b/core/res/res/values-watch/config.xml
@@ -0,0 +1,33 @@
+<?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 power and settings items due to smaller real estate. -->
+    <string-array translatable="false" name="config_globalActionsList">
+        <item>power</item>
+        <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>
+</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..5377987 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" />
 
+    <!-- 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" />
 
+    <!-- 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,7 @@
         <attr name="theme" />
         <attr name="label" />
         <attr name="icon" />
+        <attr name="banner" />
         <attr name="logo" />
         <attr name="description" />
         <attr name="permission" />
@@ -951,6 +980,7 @@
              any accounts. The type should correspond to the account authenticator type, such as
              "com.google". -->
         <attr name="requiredAccountType" format="string"/>
+        <attr name="isGame" />
     </declare-styleable>
     
     <!-- The <code>permission</code> tag declares a security permission that can be
@@ -970,6 +1000,7 @@
         <attr name="name" />
         <attr name="label" />
         <attr name="icon" />
+        <attr name="banner" />
         <attr name="logo" />
         <attr name="permissionGroup" />
         <attr name="description" />
@@ -996,6 +1027,7 @@
         <attr name="name" />
         <attr name="label" />
         <attr name="icon" />
+        <attr name="banner" />
         <attr name="logo" />
         <attr name="description" />
         <attr name="permissionGroupFlags" />
@@ -1028,6 +1060,7 @@
         <attr name="name" />
         <attr name="label" />
         <attr name="icon" />
+        <attr name="banner" />
         <attr name="logo" />
     </declare-styleable>
     
@@ -1294,6 +1327,7 @@
         <attr name="label" />
         <attr name="description" />
         <attr name="icon" />
+        <attr name="banner" />
         <attr name="logo" />
         <attr name="process" />
         <attr name="authorities" />
@@ -1375,6 +1409,7 @@
         <attr name="label" />
         <attr name="description" />
         <attr name="icon" />
+        <attr name="banner" />
         <attr name="logo" />
         <attr name="permission" />
         <attr name="process" />
@@ -1417,6 +1452,7 @@
         <attr name="label" />
         <attr name="description" />
         <attr name="icon" />
+        <attr name="banner" />
         <attr name="logo" />
         <attr name="permission" />
         <attr name="process" />
@@ -1451,6 +1487,7 @@
         <attr name="label" />
         <attr name="description" />
         <attr name="icon" />
+        <attr name="banner" />
         <attr name="logo" />
         <attr name="launchMode" />
         <attr name="screenOrientation" />
@@ -1486,6 +1523,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 +1552,7 @@
         <attr name="label" />
         <attr name="description" />
         <attr name="icon" />
+        <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 +1624,7 @@
          parent="AndroidManifestActivity AndroidManifestReceiver AndroidManifestService">
         <attr name="label" />
         <attr name="icon" />
+        <attr name="banner" />
         <attr name="logo" />
         <attr name="priority" />
     </declare-styleable>
@@ -1713,6 +1753,7 @@
         <attr name="targetPackage" />
         <attr name="label" />
         <attr name="icon" />
+        <attr name="banner" />
         <attr name="logo" />
         <attr name="handleProfiling" />
         <attr name="functionalTest" />
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index a3b8132..cafa0a5 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,6 +1117,70 @@
     <!-- 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>
@@ -1234,6 +1328,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 +1416,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/public.xml b/core/res/res/values/public.xml
index 8187939..97fd76b 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2087,4 +2087,13 @@
   <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="banner" id="0x10103f2" />
+  <public type="attr" name="windowSwipeToDismiss" id="0x10103f3" />
+  <public type="attr" name="isGame" id="0x10103f4" />
+  <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..52d90bc
--- /dev/null
+++ b/core/res/res/values/styles_micro.xml
@@ -0,0 +1,34 @@
+<?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="Widget.Micro" parent="Widget.Holo" />
+
+    <style name="Widget.Micro.TextView">
+        <item name="android:fontFamily">sans-serif-condensed</item>
+    </style>
+
+    <style name="Widget.Micro.NumberPicker">
+        <item name="android:internalLayout">@android:layout/number_picker_with_selector_wheel_micro</item>
+        <item name="android:solidColor">@android:color/transparent</item>
+        <item name="android:selectionDivider">@android:drawable/numberpicker_selection_divider</item>
+        <item name="android:selectionDividerHeight">0dip</item>
+        <item name="android:selectionDividersDistance">104dip</item>
+        <item name="android:internalMinWidth">64dip</item>
+        <item name="android:internalMaxHeight">180dip</item>
+        <item name="virtualButtonPressedDrawable">?android:attr/selectableItemBackground</item>
+        <item name="android:descendantFocusability">blocksDescendants</item>
+    </style>
+</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 1200276..bb82357 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -288,6 +288,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" />
@@ -478,7 +479,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 +988,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 +1309,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 +1377,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 +1390,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 +1463,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 +1511,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" />
@@ -1610,11 +1616,19 @@
   <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" />
diff --git a/core/res/res/values/themes_micro.xml b/core/res/res/values/themes_micro.xml
new file mode 100644
index 0000000..f51b8df
--- /dev/null
+++ b/core/res/res/values/themes_micro.xml
@@ -0,0 +1,34 @@
+<?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="textViewStyle">@android:style/Widget.Micro.TextView</item>
+        <item name="numberPickerStyle">@android:style/Widget.Micro.NumberPicker</item>
+        <item name="windowAnimationStyle">@android: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="textViewStyle">@android:style/Widget.Micro.TextView</item>
+        <item name="numberPickerStyle">@android:style/Widget.Micro.NumberPicker</item>
+        <item name="windowAnimationStyle">@android:style/Animation.SwipeDismiss</item>
+        <item name="windowIsFloating">false</item>
+        <item name="windowIsTranslucent">true</item>
+        <item name="windowSwipeToDismiss">true</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..0cd19f2
--- /dev/null
+++ b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothInstrumentation.java
@@ -0,0 +1,99 @@
+/*
+ * 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 {
+            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 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 05cca13e..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 1413319..0cdcb1c 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"
@@ -423,3 +423,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/about/dashboards/index.jd b/docs/html/about/dashboards/index.jd
index 6d29c69..92ecd24 100644
--- a/docs/html/about/dashboards/index.jd
+++ b/docs/html/about/dashboards/index.jd
@@ -61,7 +61,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 April 1, 2014.
 <br/>Any versions with less than 0.1% distribution are not shown.</em>
 </p>
 
@@ -92,7 +92,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 April 1, 2014.
 <br/>Any screen configurations with less than 0.1% distribution are not shown.</em></p>
 
 
@@ -133,17 +133,17 @@
 </tr>
 <tr>
 <td>2.0</th>
-<td>91.1%</td>
+<td>89.4%</td>
 </tr>
 <tr>
 <td>3.0</th>
-<td>8.8%</td>
+<td>10.5%</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 April 1, 2014</em></p>
 
 
 
@@ -161,17 +161,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?cht=p&chs=500x250&chco=c4df9b%2C6fad0c&chf=bg%2Cs%2C00000000&chd=t%3A1.1%2C17.8%2C0.1%2C14.3%2C61.4%2C5.3&chl=Froyo%7CGingerbread%7CHoneycomb%7CIce%20Cream%20Sandwich%7CJelly%20Bean%7CKitKat",
     "data": [
       {
         "api": 8,
         "name": "Froyo",
-        "perc": "1.2"
+        "perc": "1.1"
       },
       {
         "api": 10,
         "name": "Gingerbread",
-        "perc": "19.0"
+        "perc": "17.8"
       },
       {
         "api": 13,
@@ -181,27 +181,27 @@
       {
         "api": 15,
         "name": "Ice Cream Sandwich",
-        "perc": "15.2"
+        "perc": "14.3"
       },
       {
         "api": 16,
         "name": "Jelly Bean",
-        "perc": "35.3"
+        "perc": "34.4"
       },
       {
         "api": 17,
         "name": "Jelly Bean",
-        "perc": "17.1"
+        "perc": "18.1"
       },
       {
         "api": 18,
         "name": "Jelly Bean",
-        "perc": "9.6"
+        "perc": "8.9"
       },
       {
         "api": 19,
         "name": "KitKat",
-        "perc": "2.5"
+        "perc": "5.3"
       }
     ]
   }
@@ -218,16 +218,15 @@
       "Large": {
         "hdpi": "0.6",
         "ldpi": "0.7",
-        "mdpi": "4.3",
+        "mdpi": "4.4",
         "tvdpi": "1.5",
         "xhdpi": "0.6"
       },
       "Normal": {
         "hdpi": "33.7",
-        "ldpi": "0.2",
-        "mdpi": "13.6",
-        "xhdpi": "19.9",
-        "xxhdpi": "11.9"
+        "mdpi": "13.2",
+        "xhdpi": "19.8",
+        "xxhdpi": "12.5"
       },
       "Small": {
         "ldpi": "8.1"
@@ -235,12 +234,12 @@
       "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?cht=p&chs=400x250&chco=c4df9b%2C6fad0c&chf=bg%2Cs%2C00000000&chd=t%3A8.9%2C21.8%2C1.5%2C34.6%2C20.7%2C12.6&chl=ldpi%7Cmdpi%7Ctvdpi%7Chdpi%7Cxhdpi%7Cxxhdpi",
+    "layoutchart": "//chart.googleapis.com/chart?cht=p&chs=400x250&chco=c4df9b%2C6fad0c&chf=bg%2Cs%2C00000000&chd=t%3A4.9%2C7.8%2C79.3%2C8.1&chl=Xlarge%7CLarge%7CNormal%7CSmall"
   }
 ];
 
diff --git a/docs/html/design/index.jd b/docs/html/design/index.jd
index 9ba32dd..7c7c5d9 100644
--- a/docs/html/design/index.jd
+++ b/docs/html/design/index.jd
@@ -1,4 +1,5 @@
 page.title=Design
+page.viewport_width=970
 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/develop/index.jd b/docs/html/develop/index.jd
index 3f88b9d..eb28da8 100644
--- a/docs/html/develop/index.jd
+++ b/docs/html/develop/index.jd
@@ -1,5 +1,6 @@
 fullpage=true
 page.title=Develop
+page.viewport_width=970
 header.hide=1
 carousel=1
 tabbedList=1
diff --git a/docs/html/distribute/index.jd b/docs/html/distribute/index.jd
index 544fdff..6c6e113 100644
--- a/docs/html/distribute/index.jd
+++ b/docs/html/distribute/index.jd
@@ -1,4 +1,5 @@
 page.title=Distribute Apps
+page.viewport_width=970
 header.hide=1
 
 @jd:body
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/guide/components/intents-common.jd b/docs/html/guide/components/intents-common.jd
index 506cf9d..a0f7ce1 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>
@@ -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/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/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/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/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/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/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/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/index.jd b/docs/html/index.jd
index baeaa5b..99a469a 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>
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..e12dfd8 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
@@ -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..f9d2b15 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>
 
@@ -430,6 +430,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>
 
@@ -650,7 +663,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/tools/device.jd b/docs/html/tools/device.jd
index a1fb817..ccd5903 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>
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/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/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/11_bundles_A.png b/docs/html/wear/images/11_bundles_A.png
index 7199a1f..0ffc6ec 100644
--- a/docs/html/wear/images/11_bundles_A.png
+++ b/docs/html/wear/images/11_bundles_A.png
Binary files differ
diff --git a/docs/html/wear/images/11_bundles_B.png b/docs/html/wear/images/11_bundles_B.png
index bb751a2..c188d3d 100644
--- a/docs/html/wear/images/11_bundles_B.png
+++ b/docs/html/wear/images/11_bundles_B.png
Binary files differ
diff --git a/docs/html/wear/images/11_bundles_C.png b/docs/html/wear/images/11_bundles_C.png
new file mode 100644
index 0000000..de71c59
--- /dev/null
+++ b/docs/html/wear/images/11_bundles_C.png
Binary files differ
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/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..e723dab
--- /dev/null
+++ b/docs/html/wear/notifications/stacks.jd
@@ -0,0 +1,159 @@
+page.title=Stacking Notifications
+
+@jd:body
+
+<img src="{@docRoot}wear/images/11_bundles_C.png" height="154" width="273" style="float:right;margin:0 0 20px 40px"/>
+<img src="{@docRoot}wear/images/11_bundles_B.png" height="200" width="169" style="clear:both;float:right;margin:0 0 20px 40px" />
+<img src="{@docRoot}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>
+<br />
+<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">Create notifications in stacks</h2>
+
+<div style="float:right">
+  <script src="//ajax.googleapis.com/ajax/libs/swfobject/2.2/swfobject.js"></script>
+  <div style="width:440;height:246; padding-left:20px">
+    <object type="application/x-shockwave-flash" id="ytapiplayer" data="//www.youtube.com/v/L4LvKOTkZ7Q?enablejsapi=1&amp;playerapiid=ytplayer&amp;version=3&amp;HD=1;rel=0;showinfo=0;modestbranding;origin=developer.android.com;autohide=1" width="440" height="246" style="visibility: visible;"><param name="allowScriptAccess" value="always"></object>
+    <script type="text/javascript">
+        var params = { allowScriptAccess: "always" };
+        var atts = { id: "ytapiplayer" };
+        swfobject.embedSWF("//www.youtube.com/v/L4LvKOTkZ7Q?enablejsapi=1&playerapiid=ytplayer&version=3&HD=1;rel=0;showinfo=0;modestbranding;origin=developer.android.com;autohide=1",
+          "ytapiplayer", "440", "246", "8", null, null, params, atts);
+
+        // Callback used to pause/resume carousel based on video state
+        function onytplayerStateChange(newState) {
+           var isPaused = $("#pauseButton").hasClass("paused");
+           if ((newState == 1) || (newState == 3)) {
+           // if playing or buffering, pause the carousel
+             if (!isPaused) {
+                $("#pauseButton").click();
+             }
+           } else {
+           // otherwise, make sure carousel is running
+             if (isPaused) {
+                $("#pauseButton").click();
+             }
+           }
+        }
+
+        // Callback received when YouTube player loads to setup callback (above)
+        function onYouTubePlayerReady(playerId) {
+          var ytplayer = document.getElementById("ytapiplayer");
+          ytplayer.addEventListener("onStateChange", "onytplayerStateChange");
+        }
+
+    </script>
+  </div>
+</div>
+
+
+<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, passing the same
+group key.</p>
+
+
+<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>
+
+
+<p>It's also 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 will not appear in your stack of notifications on the wearable, but
+appears as the only notification on the handheld device.
+</p>
+
+
+<p>Here's an example that creates a stack notification for a wearable and
+a summary notification for a handset device:</p>
+
+<pre style="clear:right">
+public void onClick_button_groups () {
+    Bitmap bitmapMila = BitmapFactory.decodeResource(getResources(),
+    		R.drawable.mila128);
+
+    // Nuke all previous notifications and generate unique ids
+    NotificationManagerCompat.from(this).cancelAll();
+    int notificationId = 0;
+
+    // String to represent the group all the notifications will be a part of
+    final String GROUP_KEY_EMAILS = "group_key_messages";
+
+    // Group notification that will be visible on the phone
+    NotificationCompat.Builder builderG = new NotificationCompat.Builder(this)
+            .setContentTitle("2 Pet Notifications")
+            .setContentText("Mila and Dylan both sent messages")
+            .setSmallIcon(R.drawable.ic_launcher)
+            .setLargeIcon(bitmapMila);
+    Notification summaryNotification = new WearableNotifications
+    		.Builder(builderG)
+            .setGroup(GROUP_KEY_EMAILS, 
+            		WearableNotifications.GROUP_ORDER_SUMMARY)
+            .build();
+
+    // Separate notifications that will be visible on the watch
+    Intent viewIntent1 = new Intent(this, MainActivity.class);
+    PendingIntent viewPendingIntent1 =
+          PendingIntent.getActivity(this, notificationId+1, viewIntent1, 0);
+    NotificationCompat.Builder builder1 = new NotificationCompat.Builder(this)
+            .addAction(R.drawable.ic_action_done, "Treat Fed",
+            		viewPendingIntent1)
+            .setContentTitle("Message from Mila")
+            .setContentText("What's for dinner? "
+                            + "Can we have steak?")
+            .setSmallIcon(R.drawable.ic_launcher);
+    Notification notification1 = new WearableNotifications.Builder(builder1)
+            .setGroup(GROUP_KEY_EMAILS)
+            .build();
+
+    Intent viewIntent2 = new Intent(this, MainActivity.class);
+    PendingIntent viewPendingIntent2 =
+          PendingIntent.getActivity(this, notificationId+2, viewIntent2, 0);
+    NotificationCompat.Builder builder2 = new NotificationCompat.Builder(this)
+            .addAction(R.drawable.ic_action_done, "Water Filled",
+            		viewPendingIntent2)
+            .setContentTitle("Message from Dylan")
+            .setContentText("Can you refill our water bowl?")
+            .setSmallIcon(R.drawable.ic_launcher);
+    Notification notification2 = new WearableNotifications.Builder(builder2)
+            .setGroup(GROUP_KEY_EMAILS)
+            .build();
+
+    // Issue the group notification
+    NotificationManagerCompat notificationManager =
+    		NotificationManagerCompat.from(this);
+    notificationManager.notify(notificationId+0, summaryNotification);
+
+    // Issue the separate wear notifications
+    notificationManager.notify(notificationId+2, notification2);
+    notificationManager.notify(notificationId+1, notification1);
+}
+</pre>
+
+
+</body>
+</html>
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 436dcef..0a6e6ef 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) {
@@ -272,7 +273,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);
         }
@@ -464,7 +465,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 06a57d5..22d1871 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/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index ed00398..9a0749d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -1071,17 +1071,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..b8300af 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;
@@ -235,92 +245,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 +304,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 false;
+            }
+        };
+    }
+
     private UserInfo getCurrentUser() {
         try {
             return ActivityManagerNative.getDefault().getCurrentUser();
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..56abfb4 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -38,6 +38,7 @@
 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;
@@ -124,6 +125,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 +269,15 @@
             // 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.");
+        }
         return super.requestFeature(featureId);
     }
 
@@ -2279,7 +2290,6 @@
                     } else {
                         h = 0;
                     }
-
                     if (h > 0) {
                         final int heightSize = MeasureSpec.getSize(heightMeasureSpec);
                         heightMeasureSpec = MeasureSpec.makeMeasureSpec(
@@ -2288,6 +2298,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 +2857,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 +2913,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 +2991,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 +3063,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 +3423,55 @@
         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) {
+                Callback cb = getCallback();
+                if (cb != null) {
+                    try {
+                        cb.onWindowDismissed();
+                    } catch (AbstractMethodError e) {
+                        Log.e(TAG, "onWindowDismissed not implemented in " +
+                                cb.getClass().getSimpleName(), e);
+                    }
+                }
+            }
+        });
+        swipeDismiss.setOnSwipeProgressChangedListener(
+                new SwipeDismissLayout.OnSwipeProgressChangedListener() {
+                    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;
+                        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..2a4e059 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;
     }
 
     /*
@@ -857,7 +859,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 +887,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(
@@ -1676,7 +1679,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 +2363,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 +3420,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 +3439,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 +3618,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 +3802,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 +3820,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 +3841,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 +3870,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 +3884,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 +3952,7 @@
                             Log.w(TAG, "ITelephony threw RemoteException", ex);
                         }
                     }
-                    interceptPowerKeyDown(!isScreenOn || hungUp);
+                    interceptPowerKeyDown(!interactive || hungUp);
                 } else {
                     if (interceptPowerKeyUp(canceled)) {
                         if ((mEndcallBehavior
@@ -3968,7 +3963,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 +3974,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 +4002,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 +4091,10 @@
                 break;
             }
         }
+
+        if (isWakeKey) {
+            mPowerManager.wakeUp(event.getEventTime());
+        }
         return result;
     }
 
@@ -4122,15 +4135,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) {
@@ -4492,6 +4502,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 +4690,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,7 +4719,6 @@
 
     /** {@inheritDoc} */
     public void showBootMessage(final CharSequence msg, final boolean always) {
-        if (mHeadless) return;
         mHandler.post(new Runnable() {
             @Override public void run() {
                 if (mBootMsgDialog == null) {
@@ -5303,6 +5315,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/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 97%
rename from services/java/com/android/server/BootReceiver.java
rename to services/core/java/com/android/server/BootReceiver.java
index da1b254..bce85ce 100644
--- a/services/java/com/android/server/BootReceiver.java
+++ b/services/core/java/com/android/server/BootReceiver.java
@@ -120,6 +120,8 @@
             // 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");
+            addFileToDropBox(db, prefs, headers, "/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",
@@ -184,6 +186,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 3849ab1..8650647 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..28b1df5 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,388 @@
                         }
                     }
                 } 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.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
+        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 98%
rename from services/java/com/android/server/am/BatteryStatsService.java
rename to services/core/java/com/android/server/am/BatteryStatsService.java
index 2d59678..ff06513 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) {
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..7abf88c 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);
@@ -565,7 +567,7 @@
         final boolean mustNotify;
         boolean mustInitialize = false;
         boolean updateAutoBrightness = mTwilightChanged;
-        boolean wasDim = false;
+        boolean wasDimOrDoze = false;
         mTwilightChanged = false;
 
         synchronized (mLock) {
@@ -585,7 +587,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 +634,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 +656,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 +679,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 +690,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 +724,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 +762,9 @@
     private void blockScreenOn() {
         if (!mScreenOnWasBlocked) {
             mScreenOnWasBlocked = true;
+            mScreenOnBlockStartRealTime = SystemClock.elapsedRealtime();
             if (DEBUG) {
                 Slog.d(TAG, "Blocked screen on.");
-                mScreenOnBlockStartRealTime = SystemClock.elapsedRealtime();
             }
         }
     }
@@ -771,13 +779,17 @@
         }
     }
 
-    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 {
+                if (state != Display.STATE_OFF) {
+                    mBatteryStats.noteScreenOn();
+                } else {
+                    mBatteryStats.noteScreenOff();
+                }
+            } catch (RemoteException ex) {
+                // same process
             }
         }
     }
@@ -806,7 +818,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 +907,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 +1183,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 +1234,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 +1254,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 +1313,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 +1369,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..fd2f8a1
--- /dev/null
+++ b/services/core/java/com/android/server/dreams/DreamManagerService.java
@@ -0,0 +1,655 @@
+/*
+ * 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) {
+                        throw new IllegalStateException("This operation cannot be performed "
+                                + "because the dream has ended.");
+                    }
+                    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 8cd9d93..ff816ea 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 7df70f1..f9e79fa 100755
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -38,10 +38,11 @@
 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.ServiceThread;
 
+import com.android.server.LocalServices;
 import com.android.server.Watchdog;
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -92,6 +93,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;
@@ -130,7 +132,6 @@
 import android.util.SparseArray;
 import android.util.Xml;
 import android.view.Display;
-import android.view.WindowManager;
 
 import java.io.BufferedOutputStream;
 import java.io.File;
@@ -162,6 +163,7 @@
 import libcore.io.IoUtils;
 
 import com.android.internal.R;
+import com.android.server.storage.DeviceStorageMonitorInternal;
 
 /**
  * Keep track of all those .apks everywhere.
@@ -263,11 +265,11 @@
 
     static final String mTempContainerPrefix = "smdl2tmp";
 
+    final ServiceThread mHandlerThread;
+
     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;
@@ -1083,6 +1085,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,
@@ -1130,17 +1138,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");
@@ -2573,15 +2580,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);
@@ -7492,6 +7525,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
@@ -7509,15 +7551,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 {
@@ -8075,8 +8111,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;
@@ -9891,10 +9927,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) {
@@ -11767,12 +11803,17 @@
         return true;
     }
 
+    @Override
     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..6224ed3 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);
@@ -189,118 +197,58 @@
     }
 
     /**
-     * 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;
             }
+            mInputManagerInternal.setInteractive(interactive);
         }
     }
 
     /**
-     * Called when the device has finished waking up from sleep
-     * and the display has been turned on.
+     * Notifies that the device has finished changing interactive state.
      */
-    public void onWakeUpFinished() {
+    public void onInteractiveStateChangeFinished(boolean interactive) {
         if (DEBUG) {
-            Slog.d(TAG, "onWakeUpFinished");
-        }
-    }
-
-    /**
-     * Called when the device is going to sleep.
-     */
-    public void onGoToSleepStarted(int reason) {
-        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();
             }
         }
     }
@@ -424,12 +372,7 @@
         EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 1, 0, 0, 0);
 
         mPolicy.screenTurningOn(mScreenOnListener);
-
-        try {
-            ActivityManagerNative.getDefault().wakingUp();
-        } catch (RemoteException e) {
-            // ignore it
-        }
+        mActivityManagerInternal.wakingUp();
 
         if (ActivityManagerNative.isSystemReady()) {
             mContext.sendOrderedBroadcastAsUser(mScreenOnIntent, UserHandle.ALL, null,
@@ -480,11 +423,7 @@
         EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 0, why, 0, 0);
 
         mPolicy.screenTurnedOff(why);
-        try {
-            ActivityManagerNative.getDefault().goingToSleep();
-        } catch (RemoteException e) {
-            // ignore it.
-        }
+        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 ade8414..6845e8c 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,22 +57,30 @@
 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.Installer;
 import com.android.server.pm.PackageManagerService;
 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;
 
@@ -77,62 +90,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;
@@ -142,14 +305,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;
@@ -157,48 +317,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);
@@ -209,10 +329,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);
@@ -222,10 +338,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.
@@ -238,15 +352,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));
@@ -269,13 +383,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);
@@ -285,49 +399,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)) {
@@ -344,23 +458,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 {
@@ -397,11 +507,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 {
@@ -427,9 +537,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);
                 }
@@ -487,7 +597,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) {
@@ -567,22 +678,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 {
@@ -624,10 +725,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);
                 }
@@ -665,10 +764,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);
                 }
@@ -683,34 +783,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);
                 }
@@ -770,16 +859,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) {
@@ -800,13 +882,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");
@@ -822,9 +910,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 {
@@ -848,21 +934,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();
@@ -871,7 +946,7 @@
         }
 
         if (safeMode) {
-            ActivityManagerService.self().showSafeModeOverlay();
+            mActivityManagerService.showSafeModeOverlay();
         }
 
         // Update the configuration for this context by hand, because we're going
@@ -884,7 +959,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);
         }
@@ -896,13 +972,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;
@@ -910,10 +986,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;
@@ -923,11 +995,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
@@ -935,17 +1005,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();
@@ -983,21 +1058,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);
@@ -1006,13 +1066,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);
@@ -1038,7 +1095,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);
                 }
@@ -1049,11 +1108,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);
@@ -1064,34 +1118,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) {
@@ -1102,85 +1142,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..89c951b 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -80,6 +80,12 @@
     }
 
     @Override
+    public Intent getLeanbackLaunchIntentForPackage(String packageName) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+
     public int[] getPackageGids(String packageName) throws NameNotFoundException {
         throw new UnsupportedOperationException();
     }
@@ -338,6 +344,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/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..4bef424
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/internal/view/menu/BridgeMenuItemImpl.java
@@ -0,0 +1,47 @@
+/*
+ * 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;
+
+/**
+ * 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;
+
+    /**
+     * 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);
+    }
+
+
+    public Object getViewCookie() {
+        return viewCookie;
+    }
+
+    public void setViewCookie(Object viewCookie) {
+        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..f82ca65
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/ActionBarLayout.java
@@ -0,0 +1,382 @@
+/*
+ * 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.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) {
+                    return view.getClass().getName().equals("com.android.internal.view.menu." +
+                            "ActionMenuPresenter$OverflowMenuButton");
+                }
+            };
+            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..9787432 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,7 +176,7 @@
     @Override
     public Result init(long timeout) {
         Result result = super.init(timeout);
-        if (result.isSuccess() == false) {
+        if (!result.isSuccess()) {
             return result;
         }
 
@@ -193,6 +200,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 +233,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 +262,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 +296,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 +323,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 +343,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 +399,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 +430,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 +476,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 +484,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 +560,7 @@
                     mCanvas.setDensity(hardwareConfig.getDensity().getDpiValue());
                 }
 
-                if (freshRender && newImage == false) {
+                if (freshRender && !newImage) {
                     Graphics2D gc = mImage.createGraphics();
                     gc.setComposite(AlphaComposite.Src);
 
@@ -584,7 +575,8 @@
                 mViewRoot.draw(mCanvas);
             }
 
-            mViewInfoList = startVisitingViews(mViewRoot, 0, params.getExtendedViewInfoMode());
+            mSystemViewInfoList = visitAllChildren(mViewRoot, 0, params.getExtendedViewInfoMode(),
+                    false);
 
             // success!
             return SUCCESS.createResult();
@@ -614,6 +606,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 +637,7 @@
         BridgeContext context = getContext();
 
         // find the animation file.
-        ResourceValue animationResource = null;
+        ResourceValue animationResource;
         int animationId = 0;
         if (isFrameworkAnimation) {
             animationResource = context.getRenderResources().getFrameworkResource(
@@ -734,7 +727,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 +797,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 +861,7 @@
         }
 
         Result result = moveView(previousParent, newParentView, childView, index, layoutParams);
-        if (result.isSuccess() == false) {
+        if (!result.isSuccess()) {
             return result;
         }
 
@@ -1002,7 +995,7 @@
         }
 
         Result result = removeView(parent, childView);
-        if (result.isSuccess() == false) {
+        if (!result.isSuccess()) {
             return result;
         }
 
@@ -1030,7 +1023,7 @@
 
 
     private void findBackground(RenderResources resources) {
-        if (getParams().isBgColorOverridden() == false) {
+        if (!getParams().isBgColorOverridden()) {
             mWindowBackground = resources.findItemInTheme("windowBackground",
                     true /*isFrameworkAttr*/);
             if (mWindowBackground != null) {
@@ -1047,7 +1040,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 +1094,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 +1121,7 @@
     }
 
     private void findNavigationBar(RenderResources resources, DisplayMetrics metrics) {
-        if (hasSoftwareButtons() && mWindowIsFloating == false) {
+        if (hasSoftwareButtons() && !mWindowIsFloating) {
 
             // default value
             mNavigationBarSize = 48; // ??
@@ -1142,15 +1135,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 +1191,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 +1302,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 +1311,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 +1326,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 +1344,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 +1363,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 +1497,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 +1595,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..7b0f8f5 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",
@@ -139,6 +142,8 @@
         "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);